php实现websocket实时消息推送


Posted in PHP onMarch 30, 2018

php实现websocket实时消息推送,供大家参考,具体内容如下

php实现websocket实时消息推送

SocketService.php

<?php
/**
 * Created by xwx
 * Date: 2017/10/18
 * Time: 14:33
 */

class SocketService
{
  private $address = '0.0.0.0';
  private $port = 8083;
  private $_sockets;
  public function __construct($address = '', $port='')
  {
      if(!empty($address)){
        $this->address = $address;
      }
      if(!empty($port)) {
        $this->port = $port;
      }
  }

  public function service(){
    //获取tcp协议号码。
    $tcp = getprotobyname("tcp");
    $sock = socket_create(AF_INET, SOCK_STREAM, $tcp);
    socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);
    if($sock < 0)
    {
      throw new Exception("failed to create socket: ".socket_strerror($sock)."\n");
    }
    socket_bind($sock, $this->address, $this->port);
    socket_listen($sock, $this->port);
    echo "listen on $this->address $this->port ... \n";
    $this->_sockets = $sock;
  }

  public function run(){
    $this->service();
    $clients[] = $this->_sockets;
    while (true){
      $changes = $clients;
      $write = NULL;
      $except = NULL;
      socket_select($changes, $write, $except, NULL);
      foreach ($changes as $key => $_sock){
        if($this->_sockets == $_sock){ //判断是不是新接入的socket
          if(($newClient = socket_accept($_sock)) === false){
            die('failed to accept socket: '.socket_strerror($_sock)."\n");
          }
          $line = trim(socket_read($newClient, 1024));
          $this->handshaking($newClient, $line);
          //获取client ip
          socket_getpeername ($newClient, $ip);
          $clients[$ip] = $newClient;
          echo "Client ip:{$ip}  \n";
          echo "Client msg:{$line} \n";
        } else {
          socket_recv($_sock, $buffer, 2048, 0);
          $msg = $this->message($buffer);
          //在这里业务代码
          echo "{$key} clinet msg:",$msg,"\n";
          fwrite(STDOUT, 'Please input a argument:');
          $response = trim(fgets(STDIN));
          $this->send($_sock, $response);
          echo "{$key} response to Client:".$response,"\n";
        }
      }
    }
  }

  /**
   * 握手处理
   * @param $newClient socket
   * @return int 接收到的信息
   */
  public function handshaking($newClient, $line){

    $headers = array();
    $lines = preg_split("/\r\n/", $line);
    foreach($lines as $line)
    {
      $line = chop($line);
      if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
      {
        $headers[$matches[1]] = $matches[2];
      }
    }
    $secKey = $headers['Sec-WebSocket-Key'];
    $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
    $upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
      "Upgrade: websocket\r\n" .
      "Connection: Upgrade\r\n" .
      "WebSocket-Origin: $this->address\r\n" .
      "WebSocket-Location: ws://$this->address:$this->port/websocket/websocket\r\n".
      "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
    return socket_write($newClient, $upgrade, strlen($upgrade));
  }

  /**
   * 解析接收数据
   * @param $buffer
   * @return null|string
   */
  public function message($buffer){
    $len = $masks = $data = $decoded = null;
    $len = ord($buffer[1]) & 127;
    if ($len === 126) {
      $masks = substr($buffer, 4, 4);
      $data = substr($buffer, 8);
    } else if ($len === 127) {
      $masks = substr($buffer, 10, 4);
      $data = substr($buffer, 14);
    } else {
      $masks = substr($buffer, 2, 4);
      $data = substr($buffer, 6);
    }
    for ($index = 0; $index < strlen($data); $index++) {
      $decoded .= $data[$index] ^ $masks[$index % 4];
    }
    return $decoded;
  }

  /**
   * 发送数据
   * @param $newClinet 新接入的socket
   * @param $msg  要发送的数据
   * @return int|string
   */
  public function send($newClinet, $msg){
    $msg = $this->frame($msg);
    socket_write($newClinet, $msg, strlen($msg));
  }

  public function frame($s) {
    $a = str_split($s, 125);
    if (count($a) == 1) {
      return "\x81" . chr(strlen($a[0])) . $a[0];
    }
    $ns = "";
    foreach ($a as $o) {
      $ns .= "\x81" . chr(strlen($o)) . $o;
    }
    return $ns;
  }

  /**
   * 关闭socket
   */
  public function close(){
    return socket_close($this->_sockets);
  }
}

$sock = new SocketService();
$sock->run();

web.html

<!doctype html>
<html lang="en">
 <head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no">
 <title>websocket</title>
 </head>
 <body>
 <input id="text" value="">
 <input type="submit" value="send" onclick="start()">
 <input type="submit" value="close" onclick="close()">
<div id="msg"></div>
 <script>
 /**
 0:未连接

1:连接成功,可通讯

2:正在关闭

3:连接已关闭或无法打开
*/

  //创建一个webSocket 实例
  var webSocket = new WebSocket("ws://192.168.31.152:8083");


  webSocket.onerror = function (event){
    onError(event);
  };

  // 打开websocket
  webSocket.onopen = function (event){
    onOpen(event);
  };

  //监听消息
  webSocket.onmessage = function (event){
    onMessage(event);
  };


  webSocket.onclose = function (event){
    onClose(event);
  }

  //关闭监听websocket
  function onError(event){
    document.getElementById("msg").innerHTML = "<p>close</p>";
    console.log("error"+event.data);
  };

  function onOpen(event){
    console.log("open:"+sockState());
    document.getElementById("msg").innerHTML = "<p>Connect to Service</p>";
  };
  function onMessage(event){
    console.log("onMessage");
    document.getElementById("msg").innerHTML += "<p>response:"+event.data+"</p>"
  };

  function onClose(event){
    document.getElementById("msg").innerHTML = "<p>close</p>";
    console.log("close:"+sockState());
    webSocket.close();
  }

  function sockState(){
    var status = ['未连接','连接成功,可通讯','正在关闭','连接已关闭或无法打开'];
      return status[webSocket.readyState];
  }


 function start(event){
    console.log(webSocket);
    var msg = document.getElementById('text').value;
    document.getElementById('text').value = '';
    console.log("send:"+sockState());
    console.log("msg="+msg);
    webSocket.send("msg="+msg);
    document.getElementById("msg").innerHTML += "<p>request"+msg+"</p>"
  };

  function close(event){
    webSocket.close();
  }
 </script>
 </body>
</html>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP动态创建Web站点的方法
Aug 14 PHP
那些年一起学习的PHP(二)
Mar 21 PHP
php遍历数组的方法分享
Mar 22 PHP
使用PHP会话(Session)实现用户登陆功能
Jun 29 PHP
PHP正则提取不包含指定网址的图片地址的例子
Apr 21 PHP
Smarty模板学习笔记之Smarty简介
May 20 PHP
ThinkPHP 表单自动验证运用示例
Oct 13 PHP
PHP魔术方法的使用示例
Jun 23 PHP
php编译安装php-amq扩展简明教程
Jun 25 PHP
PHP中call_user_func_array回调函数的用法示例
Nov 26 PHP
php使用flock阻塞写入文件和非阻塞写入文件的实例讲解
Jul 10 PHP
TP5框架model常见操作示例小结【增删改查、聚合、时间戳、软删除等】
Apr 05 PHP
总结PHP内存释放以及垃圾回收
Mar 29 #PHP
PHP+Ajax实现的博客文章添加类别功能示例
Mar 29 #PHP
PHP使用文件锁解决高并发问题示例
Mar 29 #PHP
PHP实现微信支付(jsapi支付)流程步骤详解
Mar 15 #PHP
PHP实现的数组和XML文件相互转换功能示例
Mar 15 #PHP
PHP实现用户异地登录提醒功能的方法【基于thinkPHP框架】
Mar 15 #PHP
laravel框架关于搜索功能的实现
Mar 15 #PHP
You might like
建立文件交换功能的脚本(一)
2006/10/09 PHP
mysql+php分页类(已测)
2008/03/31 PHP
php一个找二层目录的小东东
2012/08/02 PHP
Dwz与thinkphp整合下的数据导出到Excel实例
2014/12/04 PHP
Windows下Apache + PHP SESSION丢失的解决过程全纪录
2015/04/07 PHP
利用PHP命令行模式采集股票趋势信息
2016/08/09 PHP
使用Rancher在K8S上部署高性能PHP应用程序的教程
2020/07/10 PHP
用正则获取指定路径文件的名称
2007/02/27 Javascript
jQuery实现优雅的弹窗效果(6)
2017/02/08 Javascript
浅谈Angular4中常用管道
2017/09/27 Javascript
Material(包括Material Icon)在Angular2中的使用详解
2018/02/11 Javascript
vue.js数据绑定操作详解
2018/04/23 Javascript
JS闭包经典实例详解
2018/12/20 Javascript
如何从零开始手写Koa2框架
2019/03/22 Javascript
使用nodejs分离html文件里的js和css详解
2019/04/12 NodeJs
ajax跨域访问遇到的问题及解决方案
2019/05/23 Javascript
jQuery实现高级检索功能
2019/05/28 jQuery
JS实现网页时钟特效
2020/03/25 Javascript
ES6的循环与可迭代对象示例详解
2021/01/31 Javascript
Python备份Mysql脚本
2008/08/11 Python
Python Mysql数据库操作 Perl操作Mysql数据库
2009/01/12 Python
在Python中处理字符串之isdecimal()方法的使用
2015/05/20 Python
日常整理python执行系统命令的常见方法(全)
2015/10/22 Python
Python正则抓取网易新闻的方法示例
2017/04/21 Python
python打包exe开机自动启动的实例(windows)
2019/06/28 Python
解决Pycharm中恢复被exclude的项目问题(pycharm source root)
2020/02/14 Python
pytorch查看通道数 维数 尺寸大小方式
2020/05/26 Python
Python DataFrame使用drop_duplicates()函数去重(保留重复值,取重复值)
2020/07/20 Python
python 代码运行时间获取方式详解
2020/09/18 Python
西雅图的买手店:Totokaelo
2019/10/19 全球购物
人力资源部培训专员岗位职责
2014/01/02 职场文书
致长跑运动员加油稿
2014/02/20 职场文书
政风行风整改方案
2014/10/25 职场文书
2014年租房协议书范本
2014/10/30 职场文书
先进个人主要事迹范文
2015/11/04 职场文书
2016年安康杯竞赛活动总结
2016/04/05 职场文书