zoukankan      html  css  js  c++  java
  • WebSocket简单实现 聊天室 swoole

    环境配置

    先开启sockets扩展

    php -m | grep sockets

    项目源码

    https://github.com/guainttt/WebSocketChat

    WebSocketSocket.php

    <?php
    /**
     * Created by PhpStorm.
     * User: SUN
     * Date: 2021/3/13
     * Time: 0:29
     */
    namespace WebSocket;
    class Socket
    {
        //服务端
        protected $master = null;
        //socket连接池
        protected $connectPool = [];
        //握手池 http升级websocket
        protected $handPool = [];
        
        public function __construct($ip,$port)
        {
            $this->startServer($ip,$port);
        }
        public function startServer($ip,$port)
        {
            $this->connectPool[] = $this->master= socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
            socket_bind($this->master,$ip,$port);
            //1000 并发数
            socket_listen($this->master,1000);
            while (true){
                $sockets = $this->connectPool;
                $write = null;
                $except = null;//排除
                //60秒 超时时间
                socket_select($sockets,$write,$except,60);
                
                //从socket里拿数据
                foreach ($sockets as $socket){
                    //服务端
                    if ($socket == $this->master){
                        //服务端 socket可读说明有新用户连接
                        $this->connectPool[] = $client = socket_accept($this->master);
                        //                     var_dump($client);exit;
                        $keyArr = array_keys($this->connectPool,$client);
                        $key = end($keyArr);
                        $this->handPool[$key] = false;
                        
                    }else{
                        //                    客户端
                        $length = socket_recv($socket,$buffer,1024,0);
                        if ($length<1){
                            //                        客户端已经断开连接了
                            //                        断开服务端连接
                            $this->close($socket);
                        }else{
                            //                        数据是正常长度
                            $key = array_search($socket,$this->connectPool);
                            //                        还没有握手
                            if ($this->handPool[$key] == false){
                                //                            握手
                                $this->handShake($socket,$buffer,$key);
                            }else{
                                //                               解帧和封帧
                                $message = $this->deFrame($buffer);
                                $message = $this->enFrame($message);
                                //发送给所有人
                                $this->send($message);
                                
                            }
                            
                        }
                        
                        
                    }
                }
            }
        }
        
        /**
         * 客户端断开连接
         * @param $socket
         */
        public function close($socket)
        {
            $key = array_search($socket,$this->connectPool);
            unset($this->connectPool[$key]);
            unset($this->handPool[$key]);
            socket_close($socket);
        }
        
        /**
         * http升级websocket
         * @param $socket
         * @param $buffer
         * @param $key
         */
        public function handShake($socket,$buffer,$key)
        {
            if(preg_match("/Sec-WebSocket-Key:s*(.*?)
    /", $buffer, $match)){
                $responseKey = base64_encode(sha1($match[1] .'258EAFA5-E914-47DA-95CA-C5AB0DC85B11',true));
                //按照协议组合信息进行返回
                //        加载头
                $resposeHeader = "HTTP/1.1 101 Switching Protocols
    ";
                $resposeHeader .= "Upgrade: websocket
    ";
                $resposeHeader .= "Sec-WebSocket-Version: 13
    ";
                $resposeHeader .= "Connection: Upgrade
    ";
                $resposeHeader .= "Sec-WebSocket-Accept: " . $responseKey . "
    
    ";
                //        发动送到客户端
                socket_write($socket,$resposeHeader,strlen($resposeHeader));
                //对已经握手的client做标志
                $this->handPool[$key]=true;
            }
        }
        
        /**
         * 数据解帧
         */
        public function deFrame($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;
        }
        /**
         * 封帧
         */
        public function enFrame($message)
        {
            $len = strlen($message);
            if ($len <= 125) {
                return "x81" . chr($len) . $message;
            } else if ($len <= 65535) {
                return "x81" . chr(126) . pack("n", $len) . $message;
            } else {
                return "x81" . char(127) . pack("xxxxN", $len) . $message;
            }
        }
        /**
         * 群聊发送给所有客户端
         */
        public function send($message)
        {
            foreach ($this->connectPool as $socket){
                if ($socket != $this->master){
                    socket_write($socket,$message,strlen($message));
                }
            }
        }
        
        
        
    }
    View Code

    调用

    server.php

    <?php
    //use WebSocketsocket;
    include __DIR__.'/WebSocket/Socket.php';
    $ip = '0.0.0.0';
    $port = 3333;
    new  WebSocketSocket($ip,$port);

    运行

    php server.php

    测试

    查看你的端口是否正常绑定

    netstat  -anp  |grep 3333

    打开chrome(火狐不行)

    var ws=new WebSocket("ws://192.168.2.234:3333");
    ws.onmessage =function(data){ console.log(data.data);}
    ws.send('bbb');

    再打开一个页面

    var ws=new WebSocket("ws://192.168.2.234:3333");
    ws.onmessage =function(data){ console.log(data.data);}
    ws.send('ttt');

    即可实现通信

     

    参考 https://blog.csdn.net/qq_27773645/article/details/94001996

    bilibili视频教程 https://www.bilibili.com/video/BV17s41177UQ?t=2653

    1 安装socket扩展

    docker-php-ext-install sockets

     

  • 相关阅读:
    解析HTTP协议六种请求方法
    金蝶
    普元
    中间件
    [CTSC2008] 网络管理
    【Uva 10498】满意值
    【SPOJ839】最优标号
    bzoj2879 [Noi2012]美食节
    bzoj3144 [Hnoi2013]切糕
    bzoj3112 [Zjoi2013]防守战线
  • 原文地址:https://www.cnblogs.com/polax/p/14529808.html
Copyright © 2011-2022 走看看