前面的文章是借鉴的
<?php /** * @Author: FatKee * @Date: 2019-01-09 12:42:28 * @Last Modified by: FatKee * @Last Modified time: 2019-01-10 16:37:13 */ class WebSocket{ //socket池 private $sockets = []; //用户池 private $users = []; //主sock private $master = NULL; //当前错误 private $error = \'\'; public function __construct($host ,$port){ $this->master = socket_create(AF_INET,SOCK_STREAM,SOL_TCP ); if($this->master === false){ $this->error = \'socket create error\'; exit; } if(socket_bind($this->master,$host,$port) === false){ $this->error = \'socket bind error\'; exit; } if(socket_listen($this->master) === false){ $this->error = \'socket listen error\'; exit; } $this->sockets[] = $this->master; $this->e(\'start:\'.$host.\'port:\' . $port); } public function run(){ while(true){ $sockets = $this->sockets; $write = NULL; $except = NULL; socket_select($sockets,$write,$except,NULL); foreach($sockets as $sock){ if($sock == $this->master){ //等待新用户 $k = uniqid(); $this->e(\'user:\'. $k . \' 加入用户池\'); $new_sock = socket_accept($this->master); $this->users[$k] = array(\'socket\' => $new_sock, \'is_hand\' => false ); $this->sockets[] = $new_sock; }else{ //接收消息的或者关闭链接 $k = $this->search($sock); if($this->users[$k][\'is_hand\'] === false){ //进行握手 $this->handshake($sock); $this->users[$k][\'is_hand\'] = true; $this->e(\'user:\'. $k . \' 握手成功\'); continue; } //读取 $byte=socket_recv($sock, $buff,20480, 0); if($byte<7){ $this->e(\'user:\'. $k . \' 退出\'); $this->close($k); continue; } //$this->e(\'user:\'. $k . \' 发送消息\'); //转发消息给别人 $this->e($k.\'群发:\'.$this->decode($buff)); $this->qunfa($sock,$this->decode($buff)); } } } } private function qunfa($sock,$str){ foreach ($this->users as $v) { if($v[\'socket\'] != $sock) $this->send($v[\'socket\'],$str); } } //寻找socket的key private function search($sock){ foreach($this->users as $k=>$v){ if($v[\'socket\'] == $sock){ return $k; } } } private function handshake($sock){ $c = socket_read($sock,1024); preg_match(\'/Sec-WebSocket-Key:(.*)/um\',$c,$str); if(isset($str[1])){ $new_key = base64_encode(sha1(trim($str[1])."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true)); $new_message = "HTTP/1.1 101 Switching Protocols\r\n"; $new_message .= "Upgrade: websocket\r\n"; $new_message .= "Sec-WebSocket-Version: 13\r\n"; $new_message .= "Connection: Upgrade\r\n"; $new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n"; socket_write($sock,$new_message,strlen($new_message)); } } //关闭链接 private function close($k){ socket_close($this->users[$k][\'socket\']); unset($this->users[$k]); $this->sockets = []; $this->sockets[] = $this->master; foreach($this->users as $v){ $this->sockets[] = $v[\'socket\']; } } public function e($str){ echo iconv(\'UTF-8\',\'GB2312\',$str) . "\r\n"; } //解析数据 private function decode($buff){ $arr[\'fin\'] = ord($buff[0]) >> 7; $arr[\'mask\'] = ord($buff[1])>>7; $arr[\'len\'] = bindec(substr(decbin(ord($buff[1])),1,7)); if($arr[\'len\'] == 126){ $arr[\'len\'] = ord($buff[2]) + ord($buff[3]) ; $maskkey = substr($buff,4,4); $data = substr($buff,8); } if($arr[\'len\'] == 127){ $arr[\'len\'] = ord($buff[2]) + ord($buff[3]) + ord($buff[4])+ ord($buff[5]); $maskkey = substr($buff,10,4); $data = substr($buff,14); } if($arr[\'len\']<=125){ $maskkey = substr($buff,2,4); $data = substr($buff,6); } $a = ""; for($i = 0 ; $i<strlen($data);$i++){ $a .= $data[$i] ^ $maskkey[$i%4]; } return $a; } private function send($sock,$str){ $bf ="\x81".chr(strlen($str)).$str; socket_write($sock,$bf,strlen($bf)); } } $socket = new WebSocket(\'192.168.2.188\',1234); $socket->run();