全站年SVIP
全站1000+试题无限查看
创建两个数组来记录连接的客户端以及握手状态
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 方法即可
php手写连接池
创建两个数组来记录连接的客户端以及握手状态
运行服务的方法
以下是某些必需的操作
关闭连接
握手操作
数据的加密与解密,以及发送信息
写完以上代码,运行 startServer 方法即可