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 相关文章推荐
Classes and Objects in PHP5-面向对象编程 [1]
Oct 09 PHP
php实现的在线人员函数库
Apr 09 PHP
领悟php接口中interface存在的意义
Jun 27 PHP
免费的ip数据库淘宝IP地址库简介和PHP调用实例
Apr 08 PHP
php实现最简单的MVC框架实例教程
Sep 08 PHP
php使用cookie保存登录用户名的方法
Jan 26 PHP
浅析Yii2 GridView实现下拉搜索教程
Apr 22 PHP
Zend Framework路由器用法实例详解
Dec 11 PHP
PHP实现绘制二叉树图形显示功能详解【包括二叉搜索树、平衡树及红黑树】
Nov 16 PHP
PHP多维数组排序array详解
Nov 21 PHP
Yii2.0框架实现带分页的多条件搜索功能示例
Feb 20 PHP
PHP强制转化的形式整理
May 22 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中时间轴开发(刚刚、5分钟前、昨天10:23等)
2011/10/03 PHP
PHP中extract()函数的妙用分析
2012/07/11 PHP
PHP防止跨域提交表单
2013/11/01 PHP
PHP实现使用优酷土豆视频地址获取swf播放器分享地址
2014/06/05 PHP
php抓取并保存网站图片的实现代码
2015/10/28 PHP
浅谈laravel aliases别名的原理
2019/10/24 PHP
Aster vs KG BO3 第一场2.18
2021/03/10 DOTA
JavaScript的漂亮的代码片段
2013/06/05 Javascript
js从10种颜色中随机取色实现每次取出不同的颜色
2013/10/23 Javascript
JavaScrip实现PHP print_r的数功能(三种方法)
2013/11/12 Javascript
JavaScript实现select添加option
2015/07/03 Javascript
基于Echarts 3.19 制作常用的图形(非静态)
2016/05/19 Javascript
微信小程序 自定义对话框实例详解
2017/01/20 Javascript
CheckBox多选取值及判断CheckBox选中是否为空的实例
2017/10/31 Javascript
微信小程序使用map组件实现检索(定位位置)周边的POI功能示例
2019/01/23 Javascript
vue-cli 3.x配置跨域代理的实现方法
2019/04/12 Javascript
基于layui内置模块(element常用元素的操作)
2019/09/20 Javascript
vue-cli2与vue-cli3在一台电脑共存的实现方法
2019/09/25 Javascript
vue项目中极验验证的使用代码示例
2019/12/03 Javascript
vscode 插件开发 + vue的操作方法
2020/06/05 Javascript
vue实现动态给id赋值,点击事件获取当前点击的元素的id操作
2020/11/09 Javascript
[06:42]DOTA2每周TOP10 精彩击杀集锦vol.1
2014/06/25 DOTA
Python MySQLdb模块连接操作mysql数据库实例
2015/04/08 Python
Python list操作用法总结
2015/11/10 Python
Python Requests 基础入门
2016/04/07 Python
Python实现利用163邮箱远程关电脑脚本
2018/02/22 Python
程序员写Python时的5个坏习惯,你有几条?
2018/11/26 Python
Django3.0 异步通信初体验(小结)
2019/12/04 Python
django实现后台显示媒体文件
2020/04/07 Python
python中的yield from语法快速学习
2020/11/06 Python
东方红海科技面试题软件测试方面
2012/02/08 面试题
会计出纳岗位职责
2013/12/25 职场文书
出纳员的岗位职责
2014/02/22 职场文书
机关干部个人对照检查材料思想汇报
2014/09/28 职场文书
2014年世界艾滋病日宣传活动总结
2014/11/18 职场文书
nginx内存池源码解析
2021/11/20 Servers