加入收藏 | 设为首页 | 会员中心 | 我要投稿 | RSS
您当前的位置:首页 > 学习资料

php实现websocket实时消息推送

时间:2021-03-21 23:32:01  来源:  作者:
php实现websocket实时消息推送


SocketService.php
  1. <?php
  2. /**
  3. * Created by xwx
  4. * Date: 2017/10/18
  5. * Time: 14:33
  6. */
  7.  
  8. class SocketService
  9. {
  10.     private $address  = '0.0.0.0';
  11.     private $port = 8083;
  12.     private $_sockets;
  13.     public function __construct($address = '', $port='')
  14.     {
  15.             if(!empty($address)){
  16.                 $this->address = $address;
  17.             }
  18.             if(!empty($port)) {
  19.                 $this->port = $port;
  20.             }
  21.     }
  22.  
  23.     public function service(){
  24.         //获取tcp协议号码。
  25.         $tcp = getprotobyname("tcp");
  26.         $sock = socket_create(AF_INET, SOCK_STREAM, $tcp);
  27.         socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);
  28.         if($sock < 0)
  29.         {
  30.             throw new Exception("failed to create socket: ".socket_strerror($sock)."\n");
  31.         }
  32.         socket_bind($sock, $this->address, $this->port);
  33.         socket_listen($sock, $this->port);
  34.         echo "listen on $this->address $this->port ... \n";
  35.         $this->_sockets = $sock;
  36.     }
  37.  
  38.     public function run(){
  39.         $this->service();
  40.         $clients[] = $this->_sockets;
  41.         while (true){
  42.             $changes = $clients;
  43.             $write = NULL;
  44.             $except = NULL;
  45.             socket_select($changes,  $write,  $except, NULL);
  46.             foreach ($changes as $key => $_sock){
  47.                 if($this->_sockets == $_sock){ //判断是不是新接入的socket
  48.                     if(($newClient = socket_accept($_sock))  === false){
  49.                         die('failed to accept socket: '.socket_strerror($_sock)."\n");
  50.                     }
  51.                     $line = trim(socket_read($newClient, 1024));
  52.                     $this->handshaking($newClient, $line);
  53.                     //获取client ip
  54.                     socket_getpeername ($newClient, $ip);
  55.                     $clients[$ip] = $newClient;
  56.                     echo  "Client ip:{$ip}   \n";
  57.                     echo "Client msg:{$line} \n";
  58.                 } else {
  59.                     socket_recv($_sock, $buffer,  2048, 0);
  60.                     $msg = $this->message($buffer);
  61.                     //在这里业务代码
  62.                     echo "{$key} clinet msg:",$msg,"\n";
  63.                     fwrite(STDOUT, 'Please input a argument:');
  64.                     $response = trim(fgets(STDIN));
  65.                     $this->send($_sock, $response);
  66.                     echo "{$key} response to Client:".$response,"\n";
  67.                 }
  68.             }
  69.         }
  70.     }
  71.  
  72.     /**
  73.      * 握手处理
  74.      * @param $newClient socket
  75.      * @return int  接收到的信息
  76.      */
  77.     public function handshaking($newClient, $line){
  78.  
  79.         $headers = array();
  80.         $lines = preg_split("/\r\n/", $line);
  81.         foreach($lines as $line)
  82.         {
  83.             $line = chop($line);
  84.             if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
  85.             {
  86.                 $headers[$matches[1]] = $matches[2];
  87.             }
  88.         }
  89.         $secKey = $headers['Sec-WebSocket-Key'];
  90.         $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
  91.         $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
  92.             "Upgrade: websocket\r\n" .
  93.             "Connection: Upgrade\r\n" .
  94.             "WebSocket-Origin: $this->address\r\n" .
  95.             "WebSocket-Location: ws://$this->address:$this->port/websocket/websocket\r\n".
  96.             "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
  97.         return socket_write($newClient, $upgrade, strlen($upgrade));
  98.     }
  99.  
  100.     /**
  101.      * 解析接收数据
  102.      * @param $buffer
  103.      * @return null|string
  104.      */
  105.     public function message($buffer){
  106.         $len = $masks = $data = $decoded = null;
  107.         $len = ord($buffer[1]) & 127;
  108.         if ($len === 126)  {
  109.             $masks = substr($buffer, 4, 4);
  110.             $data = substr($buffer, 8);
  111.         } else if ($len === 127)  {
  112.             $masks = substr($buffer, 10, 4);
  113.             $data = substr($buffer, 14);
  114.         } else  {
  115.             $masks = substr($buffer, 2, 4);
  116.             $data = substr($buffer, 6);
  117.         }
  118.         for ($index = 0; $index < strlen($data); $index++) {
  119.             $decoded .= $data[$index] ^ $masks[$index % 4];
  120.         }
  121.         return $decoded;
  122.     }
  123.  
  124.     /**
  125.      * 发送数据
  126.      * @param $newClinet 新接入的socket
  127.      * @param $msg   要发送的数据
  128.      * @return int|string
  129.      */
  130.     public function send($newClinet, $msg){
  131.         $msg = $this->frame($msg);
  132.         socket_write($newClinet, $msg, strlen($msg));
  133.     }
  134.  
  135.     public function frame($s) {
  136.         $a = str_split($s, 125);
  137.         if (count($a) == 1) {
  138.             return "\x81" . chr(strlen($a[0])) . $a[0];
  139.         }
  140.         $ns = "";
  141.         foreach ($a as $o) {
  142.             $ns .= "\x81" . chr(strlen($o)) . $o;
  143.         }
  144.         return $ns;
  145.     }
  146.  
  147.     /**
  148.      * 关闭socket
  149.      */
  150.     public function close(){
  151.         return socket_close($this->_sockets);
  152.     }
  153. }
  154.  
  155. $sock = new SocketService();
  156. $sock->run();
  157.  
  158.  
复制代码
web.html
  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4.   <meta charset="UTF-8">
  5.   <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no">
  6.   <title>websocket</title>
  7. </head>
  8. <body>
  9. <input id="text" value="">
  10. <input type="submit" value="send" onclick="start()">
  11. <input type="submit" value="close" onclick="close()">
  12. <div id="msg"></div>
  13. <script>
  14. /**
  15. 0:未连接
  16. 1:连接成功,可通讯
  17. 2:正在关闭
  18. 3:连接已关闭或无法打开
  19. */
  20.  
  21.     //创建一个webSocket 实例
  22.     var webSocket  = new  WebSocket("ws://192.168.31.152:8083");
  23.  
  24.  
  25.     webSocket.onerror = function (event){
  26.         onError(event);
  27.     };
  28.  
  29.     // 打开websocket
  30.     webSocket.onopen = function (event){
  31.         onOpen(event);
  32.     };
  33.  
  34.     //监听消息
  35.     webSocket.onmessage = function (event){
  36.         onMessage(event);
  37.     };
  38.  
  39.  
  40.     webSocket.onclose = function (event){
  41.         onClose(event);
  42.     }
  43.  
  44.     //关闭监听websocket
  45.     function onError(event){
  46.         document.getElementById("msg").innerHTML = "<p>close</p>";
  47.         console.log("error"+event.data);
  48.     };
  49.  
  50.     function onOpen(event){
  51.         console.log("open:"+sockState());
  52.         document.getElementById("msg").innerHTML = "<p>Connect to Service</p>";
  53.     };
  54.     function onMessage(event){
  55.         console.log("onMessage");
  56.         document.getElementById("msg").innerHTML += "<p>response:"+event.data+"</p>"
  57.     };
  58.  
  59.     function onClose(event){
  60.         document.getElementById("msg").innerHTML = "<p>close</p>";
  61.         console.log("close:"+sockState());
  62.         webSocket.close();
  63.     }
  64.  
  65.     function sockState(){
  66.         var status = ['未连接','连接成功,可通讯','正在关闭','连接已关闭或无法打开'];
  67.             return status[webSocket.readyState];
  68.     }
  69.  
  70.  
  71.  
  72. function start(event){
  73.         console.log(webSocket);
  74.         var msg = document.getElementById('text').value;
  75.         document.getElementById('text').value = '';
  76.         console.log("send:"+sockState());
  77.         console.log("msg="+msg);
  78.         webSocket.send("msg="+msg);
  79.         document.getElementById("msg").innerHTML += "<p>request"+msg+"</p>"
  80.     };
  81.  
  82.     function close(event){
  83.         webSocket.close();
  84.     }
  85. </script>
  86. </body>
  87. </html>
复制代码

 
来顶一下
返回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
推荐资讯
实现php间隔一段时间执行一次某段代码
实现php间隔一段时间
相关文章
    无相关信息
栏目更新
栏目热门