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 数组遍历方法大全(foreach,list,each)
Jun 30 PHP
PHP获取http请求的头信息实现步骤
Dec 16 PHP
YII中assets的使用示例
Jul 31 PHP
PHP实现PDO的mysql数据库操作类
Dec 12 PHP
php读取flash文件高宽帧数背景颜色的方法
Jan 06 PHP
php中使用gd库实现下载网页中所有图片
May 12 PHP
php使用ffmpeg获取视频信息并截图的实现方法
May 03 PHP
thinkphp3.x连接mysql数据库的方法(具体操作步骤)
May 19 PHP
php mongodb操作类 带几个简单的例子
Aug 25 PHP
关于PHP内置的字符串处理函数详解
Feb 04 PHP
PHP实现的简单操作SQLite数据库类与用法示例
Jun 19 PHP
基于win2003虚拟机中apache服务器的访问
Aug 01 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
php中使用base HTTP验证的方法
2015/04/20 PHP
简单的Jquery遮罩层代码实例
2013/11/14 Javascript
Javascript selection的兼容性写法介绍
2013/12/20 Javascript
详解JavaScript中的客户端消息框架设计原理
2015/06/24 Javascript
JavaScript返回上一页的三种方法及区别介绍
2015/07/04 Javascript
深入分析javascript中的错误处理机制
2016/07/17 Javascript
浅谈bootstrap使用中的一些问题以及解决过程
2016/10/18 Javascript
使用JavaScript实现表格编辑器(实例讲解)
2017/08/02 Javascript
JavaScript 保护变量不被随意修改的实现代码
2017/09/27 Javascript
从Vuex中取出数组赋值给新的数组,新数组push时报错的解决方法
2018/09/18 Javascript
JS原生带缩略图的图片切换效果
2018/10/10 Javascript
VuePress 快速踩坑小结
2019/02/14 Javascript
利用Webpack实现小程序多项目管理的方法
2019/02/25 Javascript
js实现多张图片每隔一秒切换一张图片
2019/07/29 Javascript
VUE.CLI4.0配置多页面入口的实现
2019/11/25 Javascript
JS数组方法reverse()用法实例分析
2020/01/18 Javascript
vue递归获取父元素的元素实例
2020/08/07 Javascript
Python 文件操作的详解及实例
2017/09/18 Python
Python内置函数reversed()用法分析
2018/03/20 Python
python实现数独游戏 java简单实现数独游戏
2018/03/30 Python
pycharm 主题theme设置调整仿sublime的方法
2018/05/23 Python
Python解决走迷宫问题算法示例
2018/07/27 Python
对numpy中数组转置的求解以及向量内积计算方法
2018/10/31 Python
Linux 修改Python命令的方法示例
2018/12/03 Python
女士时装鞋:Chinese Laundry
2018/08/29 全球购物
Vivo俄罗斯官方在线商店:中国智能手机品牌
2019/10/04 全球购物
实现向右循环移位
2014/07/31 面试题
《搭石》教学反思
2014/04/07 职场文书
公司行政专员岗位职责
2014/08/24 职场文书
2014年应急管理工作总结
2014/11/26 职场文书
给客户的感谢信
2015/01/21 职场文书
土建施工员岗位职责
2015/04/11 职场文书
成功的商业计划书这样写才最靠谱
2019/07/12 职场文书
MySQL系列之十 MySQL事务隔离实现并发控制
2021/07/02 MySQL
react 路由Link配置详解
2021/11/11 Javascript
Win11电源已接通但未充电怎么办?Win11电源已接通未充电的解决方法
2022/04/05 数码科技