博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PHP - Swoole websocket理解
阅读量:7137 次
发布时间:2019-06-28

本文共 8633 字,大约阅读时间需要 28 分钟。

php swoole实现websocket功能

1.确保安装了swoole扩展。

422101-20180117115332193-2068381547.png

2.撰写服务程序

on('open', function ($ws, $request) { echo "connection open: {$request->fd}\n"; $ws->push($request->fd, "hello, welcome\n"); }); //监听WebSocket消息事件 $ws->on('message', function ($ws, $frame) { echo "Message:".$frame->data."\n"; foreach($ws->connections as $key => $fd) { $ws->push($fd, "{$frame->data}"); } }); //监听WebSocket连接关闭事件 $ws->on('close', function ($ws, $fd) { echo "client-{$fd} is closed\n"; }); $ws->start();

3.开启服务

[root@localhost swooleTest]# php ws_serv.php

4.查看服务是否开启

[root@localhost swooleTest]# netstat -anp | grep :9502tcp        0      0 0.0.0.0:9502                0.0.0.0:*                   LISTEN      3502/php

查看进程情况

[root@localhost swooleTest]# ps -ef | grep 3502root       3502   2903  0 21:09 pts/1    00:00:00 php ws_serv.phproot       3503   3502  0 21:09 pts/1    00:00:00 php ws_serv.php

这个时候需要客户端连接测试了。

客户端可以是PHP,也可以是JS中的客户端。

下面通过JS连接websocket:

当执行客户端连接和发送消息的时候,服务端能够监听到。

[root@localhost swooleTest]# php ws_serv.php connection open: 1Message:我是jq,我连接了。

当其他客户端,发送消息的时候,服务端都能监听到。然后向其他在线的客户端发送消息。

下面是php客户端连接的情况:

setHeaders(['Trace-Id' => md5(time()),]);$cli->on('message', function ($_cli, $frame) { var_dump($frame);});$cli->upgrade('/', function ($cli) { echo $cli->body; $cli->push("hello world");});
[root@localhost swooleTest]# php async_client.php object(Swoole\WebSocket\Frame)#3 (3) {  ["finish"]=>  bool(true)  ["opcode"]=>  int(1)  ["data"]=>  string(11) "hello world"}

服务端也监听到了。

[root@localhost swooleTest]# php ws_serv.php connection open: 1Message:我是jq,我连接了。connection open: 2Message:hello world

客户端同样也能监听到其他客户端的情况。

[root@localhost swooleTest]# php async_client.php object(Swoole\WebSocket\Frame)#3 (3) {  ["finish"]=>  bool(true)  ["opcode"]=>  int(1)  ["data"]=>  string(11) "hello world"}object(Swoole\WebSocket\Frame)#3 (3) {  ["finish"]=>  bool(true)  ["opcode"]=>  int(1)  ["data"]=>  string(26) "我是jq,我连接了。"}

同步WebSocketClient.php,sync_client.php

host = $host; $this->port = $port; $this->path = $path; $this->origin = $origin; $this->key = $this->generateToken(self::TOKEN_LENGHT); } /** * Disconnect on destruct */ function __destruct() { $this->disconnect(); } /** * Connect client to server * * @return $this */ public function connect() { $this->socket = new \swoole_client(SWOOLE_SOCK_TCP); if (!$this->socket->connect($this->host, $this->port)) { return false; } $this->socket->send($this->createHeader()); return $this->recv(); } public function getSocket() { return $this->socket; } /** * Disconnect from server */ public function disconnect() { $this->connected = false; $this->socket->close(); } public function close($code = self::CLOSE_NORMAL, $reason = '') { $data = pack('n', $code) . $reason; return $this->socket->send(swoole_websocket_server::pack($data, self::OPCODE_CONNECTION_CLOSE, true)); } public function recv() { $data = $this->socket->recv(); if ($data === false) { echo "Error: {$this->socket->errMsg}"; return false; } $this->buffer .= $data; $recv_data = $this->parseData($this->buffer); if ($recv_data) { $this->buffer = ''; return $recv_data; } else { return false; } } /** * @param string $data * @param string $type * @param bool $masked * @return bool */ public function send($data, $type = 'text', $masked = false) { switch($type) { case 'text': $_type = WEBSOCKET_OPCODE_TEXT; break; case 'binary': case 'bin': $_type = WEBSOCKET_OPCODE_BINARY; break; case 'ping': $_type = WEBSOCKET_OPCODE_PING; break; default: return false; } return $this->socket->send(swoole_websocket_server::pack($data, $_type, true, $masked)); } /** * Parse received data * * @param $response */ private function parseData($response) { if (!$this->connected) { $response = $this->parseIncomingRaw($response); if (isset($response['Sec-Websocket-Accept']) && base64_encode(pack('H*', sha1($this->key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))) === $response['Sec-Websocket-Accept'] ) { $this->connected = true; return true; } else { throw new \Exception("error response key."); } } $frame = swoole_websocket_server::unpack($response); if ($frame) { return $this->returnData ? $frame->data : $frame; } else { throw new \Exception("swoole_websocket_server::unpack failed."); } } /** * Create header for websocket client * * @return string */ private function createHeader() { $host = $this->host; if ($host === '127.0.0.1' || $host === '0.0.0.0') { $host = 'localhost'; } return "GET {$this->path} HTTP/1.1" . "\r\n" . "Origin: {$this->origin}" . "\r\n" . "Host: {$host}:{$this->port}" . "\r\n" . "Sec-WebSocket-Key: {$this->key}" . "\r\n" . "User-Agent: PHPWebSocketClient/" . self::VERSION . "\r\n" . "Upgrade: websocket" . "\r\n" . "Connection: Upgrade" . "\r\n" . "Sec-WebSocket-Protocol: wamp" . "\r\n" . "Sec-WebSocket-Version: 13" . "\r\n" . "\r\n"; } /** * Parse raw incoming data * * @param $header * * @return array */ private function parseIncomingRaw($header) { $retval = array(); $content = ""; $fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $header)); foreach ($fields as $field) { if (preg_match('/([^:]+): (.+)/m', $field, $match)) { $match[1] = preg_replace_callback('/(?<=^|[\x09\x20\x2D])./', function ($matches) { return strtoupper($matches[0]); }, strtolower(trim($match[1]))); if (isset($retval[$match[1]])) { $retval[$match[1]] = array($retval[$match[1]], $match[2]); } else { $retval[$match[1]] = trim($match[2]); } } else { if (preg_match('!HTTP/1\.\d (\d)* .!', $field)) { $retval["status"] = $field; } else { $content .= $field . "\r\n"; } } } $retval['content'] = $content; return $retval; } /** * Generate token * * @param int $length * * @return string */ private function generateToken($length) { $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"§$%&/()=[]{}'; $useChars = array(); // select some random chars: for ($i = 0; $i < $length; $i++) { $useChars[] = $characters[mt_rand(0, strlen($characters) - 1)]; } // Add numbers array_push($useChars, rand(0, 9), rand(0, 9), rand(0, 9)); shuffle($useChars); $randomString = trim(implode('', $useChars)); $randomString = substr($randomString, 0, self::TOKEN_LENGHT); return base64_encode($randomString); } /** * Generate token * * @param int $length * * @return string */ public function generateAlphaNumToken($length) { $characters = str_split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'); srand((float)microtime() * 1000000); $token = ''; do { shuffle($characters); $token .= $characters[mt_rand(0, (count($characters) - 1))]; } while (strlen($token) < $length); return $token; }}
connect();//echo $data;$data = "data";for ($i = 0; $i < $count; $i++){ $client->send("hello swoole, number:" . $i . " data:" . $data); echo "send over!" . PHP_EOL;}echo PHP_EOL . "======" . PHP_EOL;sleep(1);echo 'finish' . PHP_EOL;

422101-20180117141612521-807327395.png

422101-20180117141631599-636100885.png

具体的案例可以参考:

转载地址:http://xbvrl.baihongyu.com/

你可能感兴趣的文章
Java程序员从笨鸟到菜鸟之(九十八)深入java虚拟机(七)深入源码看java类加载器ClassLoader...
查看>>
kickstart及引导镜像制作
查看>>
python进程
查看>>
Vue.js笔记,从入门到精通
查看>>
Skype for Business实战演练之七:创建并发布新的拓扑
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
ADMT3.2域迁移之Server2003至Server2012系列(六)安装SQL Server2008
查看>>
webpack源码分析(1)----- webpack.cmd
查看>>
Oracle存在修改,不存在插入记录
查看>>
Java实现欢迎登录学员管理系统
查看>>
自我剖析,坚持有多难?
查看>>
find 指令
查看>>
系统学习redis之六——redis数据类型之set数据类型及操作
查看>>
【简报】帮助开发人员在线了解CSS Filter特性的工具 - CSS FilterLab
查看>>
软考信息系统监理师:2016年4月22日作业
查看>>
META-INF\MANIFEST.MF (系统找不到指定的路径)
查看>>
俄罗斯方块软件:C语言应用初步感受
查看>>
【安全牛学习笔记】收集敏感数据、隐藏痕迹
查看>>
LinkedME|Deep Linking技术你真的了解吗
查看>>