php手写连接池

创建两个数组来记录连接的客户端以及握手状态


  private $master = null; //服务端
  private $connectPool = []; //客户端连接池
  private $handShakePool = []; //握手连接池


运行服务的方法


public function startServer($ip, $port) {
        $this->connectPool[] = $this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);//创建服务端
        socket_bind($this->master, $ip, $port);//绑定服务端ip,端口
        socket_listen($this->master, 1000);//监听,最多同时监听1000个客户端
        while(true) {
            $sockets = $this->connectPool;
            $write = $excpet = null;
            socket_select($sockets, $write, $excpet, 60);//阻塞模式


            foreach($sockets as $socket) {//监听消息
                if($socket == $this->master) {//添加新客户端
                    $this->connectPool[] = $client = socket_accept($this->master);
                    $keyArr = array_keys($this->connectPool, $client);
                    $key = end($keyArr);
                    $this->handShakePool[$key] = false;
                } else {
                    $length = socket_recv($socket, $buffer, 1024, 0);
                    if($length<1) {//当长度小于7,说明当前客户端连接已断开
                        $this->close($socket);//服务端关闭断开连接的客户端
                    } else {
                        $key = array_search($this->master, $this->connectPool);
                        if($this->handShakePool[$key] == false) {//进行握手
                            $this->handShake($socket, $buffer, $key);
                        } else {//发送消息,可根据具体业务进行调整
                            $msg = $this->deFrame($buffer);
                            $msg = $this->enFrame($msg);
                            $this->send($socket, $msg);
                        }
                    }
                }
            }
        }
    }


以下是某些必需的操作

关闭连接


// 客户端断开连接
    public function close($socket) {
        $key = array_search($socket, $this->connectPool);
        unset($this->connectPool[$key]);
        unset($this->handShakePool[$key]);
        socket_close($socket);
        echo("有客户端断开连接\n");
    }



握手操作


//握手
    public function handShake($socket ,$buffer, $key) {
        if(preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $buffer, $match)) {
            $responseKey = base64_encode(sha1($match[1].'258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
            $upgrade = "HTTP/1.1 101 Switching Protocol\r\n".
                        "Upgrade: websocket\r\n".
                        "Connection: Upgrade\r\n".
                        "Sec-WebSocket-Accept: ".$responseKey."\r\n\r\n";
            socket_write($socket, $upgrade, strlen($upgrade));
            $this->handShakePool[$key] = true;
        }
        echo("新建握手,当前客户端数量=>".(sizeof($this->handShakePool)-1)."\n");
    }


数据的加密与解密,以及发送信息



//数据封帧
    public function enFrame($msg) {
        $len = strlen($msg);
        if($len<=125) {
            return "\x81".chr($len).$msg;
        } else if($len <= 65535) {
            return "\x81".chr(126).pack("n",$len).$msg;
        } else {
            return "\x81".chr(127).pack("xxxxN",$len).$msg;
        }
    }


    //数据解帧
    public function deFrame($buffer) {
        $len = $masks = $data = $decode = 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++) {
            $decode .= $data[$index]^$masks[$index*4];
        }
        return $decode;
    }


    //发送信息
    public function send($socket, $msg) {
        socket_write($socket, $msg);
        echo("给{$socket}发送{$msg}\n");
    }


写完以上代码,运行 startServer 方法即可


 0
 0
 分享
评论图片
评论