实现多个用户连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
<?php //握手协议 function doHandShake($socket, $buffer) { list($resource, $host, $origin, $key) = getHeaders($buffer); $upgrade = "HTTP/1.1 101 Switching Protocol\r\n" . "Upgrade: websocket\r\n" . "Connection: Upgrade\r\n" . "Sec-WebSocket-Accept: " . calcKey($key) . "\r\n\r\n"; //必须以两个回车结尾 echo $upgrade; socket_write($socket, $upgrade, strlen($upgrade)); return true; } //获取请求头 function getHeaders($req) { $r = $h = $o = $key = null; if (preg_match("/GET (.*) HTTP/", $req, $match)) { $r = $match[1]; } if (preg_match("/Host: (.*)\r\n/", $req, $match)) { $h = $match[1]; } if (preg_match("/Origin: (.*)\r\n/", $req, $match)) { $o = $match[1]; } if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $req, $match)) { $key = $match[1]; } return [$r, $h, $o, $key]; } //验证socket function calcKey($key) { //基于websocket version 13 $accept = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)); return $accept; } //解码 解析websocket数据帧 function decode($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; } function encode($buffer) { $len = strlen($buffer); $first_byte = "\x81"; if ($len <= 125) { $encode_buffer = $first_byte . chr($len) . $buffer; } else { if ($len <= 65535) { $encode_buffer = $first_byte . chr(126) . pack("n", $len) . $buffer; } else { //pack("xxxN", $len)pack函数只处理2的32次方大小的文件,实际上2的32次方已经4G了。 $encode_buffer = $first_byte . chr(127) . pack("xxxxN", $len) . $buffer; } } return $encode_buffer; } $handShake = []; $readType = PHP_BINARY_READ; $sockets = []; $master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_bind($master, '0.0.0.0', 8200); socket_listen($master); $sockets[] = $master; while (true) { echo "start while\n"; $tempSocket = $sockets; $write = null; $except = null; // 阻塞(tv_sec 为 NULL),直到有新的客户端连接或者已连接的客户端传入数据 socket_select($tempSocket,$write,$except,NULL); var_dump($tempSocket); foreach ($tempSocket as $index => $socket) { if ($socket == $master) { // 新的客户端连接(它等于 socket_create 创建的资源) echo "accept \n"; array_push($sockets,socket_accept($socket)); } else { // 已连接的客户端 echo "read \n"; if (($buf = socket_read($socket, 2048, $readType)) != '') { if (!isset($handShake[$index])) { echo $buf; echo "\n"; doHandShake($socket, $buf); $handShake[$index] = true; } else { echo decode($buf); $response = 'This is response'; $response = encode($response); socket_write($socket, $response, strlen($response)); echo "\n"; } } } } echo "end while\n"; } |