zoukankan      html  css  js  c++  java
  • php WebSocket 简单实现demo

    WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

    WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

    在 WebSocket API 中,浏览器和服务器只需要完成一次握手的动作,两者就形成了一条快速通道创建持久性的连接,两者之间就直接可以数据互相传送。(长连接,循环连接的不算)

    现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。

    这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

    php应用实现webSocket更多使用workerman或swoole框架.

    简单实现webSocket(demo)  代码点击View Code查看

    serverSocket.php文件

      1 <?php
      2 
      3 class SocketService
      4 {
      5     private $address;
      6     private $port;
      7     private $_sockets;
      8     public function __construct($address = '', $port='')
      9     {
     10             if(!empty($address)){
     11                 $this->address = $address;
     12             }
     13             if(!empty($port)) {
     14                 $this->port = $port;
     15             }
     16     }
     17  
     18     public function service(){
     19         //获取tcp协议号码。
     20         $tcp = getprotobyname("tcp");
     21         $sock = socket_create(AF_INET, SOCK_STREAM, $tcp);
     22         socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);
     23         if($sock < 0)
     24         {
     25             throw new Exception("failed to create socket: ".socket_strerror($sock)."
    ");
     26         }
     27         socket_bind($sock, $this->address, $this->port);
     28         socket_listen($sock, $this->port);
     29         echo "listen on $this->address $this->port ... 
    ";
     30         $this->_sockets = $sock;
     31     }
     32  
     33     public function run(){
     34         $this->service();
     35         $clients[] = $this->_sockets;
     36         while (true){
     37             $changes = $clients;
     38             $write = NULL;
     39             $except = NULL;
     40             socket_select($changes,  $write,  $except, NULL);
     41             foreach ($changes as $key => $_sock){
     42                 if($this->_sockets == $_sock){ //判断是不是新接入的socket
     43                     if(($newClient = socket_accept($_sock))  === false){
     44                         die('failed to accept socket: '.socket_strerror($_sock)."
    ");
     45                     }
     46                     $line = trim(socket_read($newClient, 1024));
     47                     $this->handshaking($newClient, $line);
     48                     //获取client ip
     49                     socket_getpeername ($newClient, $ip);
     50                     $clients[$ip] = $newClient;
     51                     echo  "Client ip:{$ip}   
    ";
     52                     echo "Client msg:{$line} 
    ";
     53                 } else {
     54                     socket_recv($_sock, $buffer,  2048, 0);
     55                     $msg = $this->message($buffer);
     56                     //在这里业务代码
     57                     echo "{$key} clinet msg:",$msg,"
    ";
     58                     fwrite(STDOUT, 'Please input a argument:');
     59                     $response = trim(fgets(STDIN));
     60                     $this->send($_sock, $response);
     61                     echo "{$key} response to Client:".$response,"
    ";
     62                 }
     63             }
     64         }
     65     }
     66  
     67     /**
     68      * 握手处理
     69      * @param $newClient socket
     70      * @return int  接收到的信息
     71      */
     72     public function handshaking($newClient, $line){
     73  
     74         $headers = array();
     75         $lines = preg_split("/
    /", $line);
     76         foreach($lines as $line)
     77         {
     78             $line = chop($line);
     79             if(preg_match('/A(S+): (.*)z/', $line, $matches))
     80             {
     81                 $headers[$matches[1]] = $matches[2];
     82             }
     83         }
     84         $secKey = $headers['Sec-WebSocket-Key'];
     85         $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
     86         $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake
    " .
     87             "Upgrade: websocket
    " .
     88             "Connection: Upgrade
    " .
     89             "WebSocket-Origin: $this->address
    " .
     90             "WebSocket-Location: ws://$this->address:$this->port/websocket/websocket
    ".
     91             "Sec-WebSocket-Accept:$secAccept
    
    ";
     92         return socket_write($newClient, $upgrade, strlen($upgrade));
     93     }
     94  
     95     /**
     96      * 解析接收数据
     97      * @param $buffer
     98      * @return null|string
     99      */
    100     public function message($buffer){
    101         $len = $masks = $data = $decoded = null;
    102         $len = ord($buffer[1]) & 127;
    103         if ($len === 126)  {
    104             $masks = substr($buffer, 4, 4);
    105             $data = substr($buffer, 8);
    106         } else if ($len === 127)  {
    107             $masks = substr($buffer, 10, 4);
    108             $data = substr($buffer, 14);
    109         } else  {
    110             $masks = substr($buffer, 2, 4);
    111             $data = substr($buffer, 6);
    112         }
    113         for ($index = 0; $index < strlen($data); $index++) {
    114             $decoded .= $data[$index] ^ $masks[$index % 4];
    115         }
    116         return $decoded;
    117     }
    118  
    119     /**
    120      * 发送数据
    121      * @param $newClinet 新接入的socket
    122      * @param $msg   要发送的数据
    123      * @return int|string
    124      */
    125     public function send($newClinet, $msg){
    126         $msg = $this->frame($msg);
    127         socket_write($newClinet, $msg, strlen($msg));
    128     }
    129  
    130     public function frame($s) {
    131         $a = str_split($s, 125);
    132         if (count($a) == 1) {
    133             return "x81" . chr(strlen($a[0])) . $a[0];
    134         }
    135         $ns = "";
    136         foreach ($a as $o) {
    137             $ns .= "x81" . chr(strlen($o)) . $o;
    138         }
    139         return $ns;
    140     }
    141  
    142     /**
    143      * 关闭socket
    144      */
    145     public function close(){
    146         return socket_close($this->_sockets);
    147     }
    148 }
    149  
    150 $sock = new SocketService('127.0.0.1','9000');
    151 $sock->run();
    View Code

    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     //创建一个webSocket 实例
    21     var webSocket  = new  WebSocket("ws://127.0.0.1:9000");
    22  
    23  
    24     webSocket.onerror = function (event){
    25         onError(event);
    26     };
    27  
    28     // 打开websocket
    29     webSocket.onopen = function (event){
    30         onOpen(event);
    31     };
    32  
    33     //监听消息
    34     webSocket.onmessage = function (event){
    35         onMessage(event);
    36     };
    37  
    38  
    39     webSocket.onclose = function (event){
    40         onClose(event);
    41     }
    42  
    43     //关闭监听websocket
    44     function onError(event){
    45         document.getElementById("msg").innerHTML = "<p>close</p>";
    46         console.log("error"+event.data);
    47     };
    48  
    49     function onOpen(event){
    50         console.log("open:"+sockState());
    51         document.getElementById("msg").innerHTML = "<p>Connect to Service</p>";
    52     };
    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     function start(event){
    71         console.log(webSocket);
    72         var msg = document.getElementById('text').value;
    73         document.getElementById('text').value = '';
    74         console.log("send:"+sockState());
    75         console.log("msg="+msg);
    76         webSocket.send("msg="+msg);
    77         document.getElementById("msg").innerHTML += "<p>request"+msg+"</p>"
    78     };
    79  
    80     function close(event){
    81         webSocket.close();
    82     }
    83  </script>
    84  </body>
    85 </html>
    View Code

     

    运行操作结果:

    准备工作开启扩展: php需要打开websocket的扩展,在php安装目录下的php.ini文件   extension=php_sockets.dll

    先执行脚本 例如: php -q serverSocket.php

    后执行页面 例如: http://web.html

     

     

  • 相关阅读:
    d3.js了解
    java常用验证码
    连接数据库的配置文件
    MD5加密的使用
    ssm下载文件
    Ajax基于rest风格上传图片
    web常见页面错误整理
    前后端一起用cookie来保存密码
    通用mapper插件
    ssm的maven依赖,直接复制可以使用
  • 原文地址:https://www.cnblogs.com/cxx8181602/p/10142140.html
Copyright © 2011-2022 走看看