PHP 之phpsocket.io简易聊天室
一、安装
composer require workerman/phpsocket.io
二、服务端和客户端连接
<?php require_once './vendor/autoload.php'; use Workerman\Worker; use PHPSocketIO\SocketIO; $io = new SocketIO(3120); // 当有客户端连接时 $io->on('connection', function($socket)use($io){ // 定义chat message事件回调函数 $socket->on('chat message', function($data)use($io){ // 触发所有客户端定义的chat message from server事件 var_dump($data); $io->emit('chat message from server', $data); }); }); Worker::runAll();
三、客户端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>聊天室</title> </head> <body> <div id="msg_box"> </div> <div id="input-box"> <input type="text" id="msg_input"><button onclick="send()">发送</button> </div> <script src='https://lib.baomitu.com/socket.io/1.7.4/socket.io.min.js'></script> <script> // 连接服务端 var socket = io('http://127.0.0.1:3120'); function send() { var msg = document.querySelector('#msg_input').value; socket.emit('chat message', msg); document.querySelector('#msg_input').value = ''; } // 服务端通过emit('chat message from server', $msg)触发客户端的chat message from server事件 socket.on('chat message from server', function(msg){ var oDiv = document.createElement('div'); oDiv.innerHTML = msg; document.querySelector('#msg_box').appendChild(oDiv); }); </script> </body> </html>
四、广播给客户端
<?php /** * Created by PhpStorm. * User: Administrator * Date: 2023/12/30 0030 * Time: 13:21 */ class SocketIO { /** * 发送数据 * @param null $host * @param null $port * @param string $action * @param null $data * @param string $address * @param string $transport * @return bool */ public function send($host = null, $port = null, $action = "message", $data = null, $address = "/socket.io/?EIO=2", $transport = 'websocket') { $fd = fsockopen($host, $port, $errno, $errstr); if (!$fd) { return false; } //Can't connect tot server $key = $this->generateKey(); $out = "GET $address&transport=$transport HTTP/1.1\r\n"; $out .= "Host: http://$host:$port\r\n"; $out .= "Upgrade: WebSocket\r\n"; $out .= "Connection: Upgrade\r\n"; $out .= "Sec-WebSocket-Key: $key\r\n"; $out .= "Sec-WebSocket-Version: 13\r\n"; $out .= "Origin: *\r\n\r\n"; fwrite($fd, $out); // 101 switching protocols, see if echoes key $result = fread($fd, 10000); preg_match('#Sec-WebSocket-Accept:\s(.*)$#mU', $result, $matches); $keyAccept = trim($matches[1]); $expectedResonse = base64_encode(pack('H*', sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))); $handshaked = ($keyAccept === $expectedResonse) ? true : false; if ($handshaked) { if ($action){ fwrite($fd, $this->hybi10Encode('42["' . $action . '", "' . addslashes($data) . '"]')); }else{ fwrite($fd, $this->hybi10Encode(addslashes($data))); } $content = ''; while (!feof($fd)) { stream_set_timeout($fd, 1); $content .= fread($fd, 1024); $info = stream_get_meta_data($fd); if ($info['timed_out']) { break; } } //fread($fd,1000000); fclose($fd); return true; } else { return false; } } private function generateKey($length = 16) { $c = 0; $tmp = ''; while ($c++ * 16 < $length) { $tmp .= md5(mt_rand(), true); } return base64_encode(substr($tmp, 0, $length)); } private function hybi10Encode($payload, $type = 'text', $masked = true) { $frameHead = array(); $payloadLength = strlen($payload); switch ($type) { case 'text': $frameHead[0] = 129; break; case 'close': $frameHead[0] = 136; break; case 'ping': $frameHead[0] = 137; break; case 'pong': $frameHead[0] = 138; break; } if ($payloadLength > 65535) { $payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8); $frameHead[1] = ($masked === true) ? 255 : 127; for ($i = 0; $i < 8; $i++) { $frameHead[$i + 2] = bindec($payloadLengthBin[$i]); } if ($frameHead[2] > 127) { $this->close(1004); return false; } } elseif ($payloadLength > 125) { $payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8); $frameHead[1] = ($masked === true) ? 254 : 126; $frameHead[2] = bindec($payloadLengthBin[0]); $frameHead[3] = bindec($payloadLengthBin[1]); } else { $frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength; } foreach (array_keys($frameHead) as $i) { $frameHead[$i] = chr($frameHead[$i]); } if ($masked === true) { $mask = array(); for ($i = 0; $i < 4; $i++) { $mask[$i] = chr(rand(0, 255)); } $frameHead = array_merge($frameHead, $mask); } $frame = implode('', $frameHead); for ($i = 0; $i < $payloadLength; $i++) { $frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i]; } return $frame; } } $socket = new SocketIO(); //发送消息到服务端,广播消息给所有客户端 $res = $socket->send('127.0.0.1', 3120, 'chat message', 'this is a test'); var_dump($res);
五、文档
https://www.workerman.net/phpsocket_io