PHP进阶之利用Swoole实现一个简单的WebSocket多人聊天室
简单分析一下做聊天室都需要干些什么?
1、首先要有一台WebSocket
服务器
2、使用WebSocket
协议与服务器进行通信
那什么是WebSocket协议呢?
WebSocket
是HTML5
开始提供的一种在单个TCP
连接上进行全双工通讯的协议
在WebSocket API
中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道,两者之间就直接可以数据互相传送
浏览器通过JavaScript
向服务器发出建立WebSocket
连接的请求,连接建立以后,客户端和服务器端就可以通过TCP
连接直接交换数据
简单的来说,WebSocket
只是一个网络通信协议
就像HTTP
、FTP
等都是网络通信的协议,相对于HTTP
这种非持久的协议来说,WebSocket
是一个持久化网络通信的协议
环境依赖:
这就不用多说了,Linux
的服务器,装好PHP
和Swoole
,因为只是一个简单的DEMO,就不存数据了
搭建流程
1、首先有握手信号标识是否成功,成功之后调用回调函数onOpen
,这个是可以不设置的,一般用作于欢迎信息之类的
Swoole
的文档解释如下:
当WebSocket
客户端与服务器建立连接并完成握手后会回调此函数
function onOpen(swoole_websocket_server $svr, swoole_http_request $req);
- $req 是一个Http请求对象,包含了客户端发来的握手请求信息
- onOpen事件函数中可以调用push向客户端发送数据或者调用close关闭连接
- onOpen事件回调是可选的
2、当服务器收到来自客户端的数据帧时会回调onMessage
函数,客户端发来数据,我们再此函数来将数据广播出去就形成了聊天,经过各种处理形成一个成型的聊天室
Swoole
的文档解释如下:
当服务器收到来自客户端的数据帧时会回调此函数
function onMessage(swoole_websocket_server $server, swoole_websocket_frame $frame);
- $frame 是
swoole_websocket_frame
对象,包含了客户端发来的数据帧信息 onMessage
回调必须被设置,未设置服务器将无法启动- 客户端发送的
ping
帧不会触发onMessage
,底层会自动回复pong
包
3、在onMessage
如何发送数据?
向WebSocket
客户端连接推送数据,长度最大不得超过2M
function swoole_websocket_server->push(int $fd, string $data, int $opcode = 1, bool $finish = true);
- $fd 客户端连接的ID,如果指定的$fd对应的TCP连接并非
websocket
客户端,将会发送失败 - $data 要发送的数据内容
- $opcode,指定发送数据内容的格式,默认为文本。发送二进制内容$opcode参数需要设置为
WEBSOCKET_OPCODE_BINARY
- 发送成功返回true,发送失败返回false
swoole_websocket_server->push在swoole-1.7.11以上版本可用
代码实现
通过上面的介绍,下面就直接上代码了,在环境目录中间一个名为WebSocket的PHP文件,你也可以换
<?php // +---------------------------------------------------------------------- // | Swoole聊天室demo // +---------------------------------------------------------------------- // | IhadPHP [ 学无止境,编码不止,开源为盼 ] // +---------------------------------------------------------------------- // | Copyright (c) 2017 - 2018 https://qq52o.me, All rights reserved. // +---------------------------------------------------------------------- // | Author: 沈唁 <52o@qq52o.cn> // +---------------------------------------------------------------------- # 定义clientFds数组 保存所有websocket连接 $clientFds = []; # 创建websocket服务 $server = new swoole_websocket_server("0.0.0.0", 9501); # 握手成功 触发回调函数 $server->on('open', function (swoole_websocket_server $server, $request) use (&$clientFds) { # echo "server: handshake success with fd{$request->fd}\n"; # 将所有客户端连接标识,握手成功后保存到数组中 $clientFds[] = $request->fd; }); # 收到消息 触发回调函数 $server->on('message', function (swoole_websocket_server $server, $frame) use (&$clientFds) { # echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n"; # $server->push($frame->fd, "this is server"); # 当有用户发送信息,发送广播通知所有用户 foreach ($clientFds as $fd) { $server->push($fd, $frame->data); } }); # 关闭连接 触发回调函数 $server->on('close', function ($ser, $fd) use (&$clientFds) { # echo "client {$fd} closed\n"; # 关闭会话 销毁标识fd # 根据value 去数组中找对应的key $res = array_search($fd, $clientFds, true); unset($clientFds[$res]); }); # 启动websocket服务 $server->start();
然后我们在cli
下启动服务
php /home/wwwroot/default/WebSocket.php
前端搞一个客户端client
链接服务器进行通讯,目前大部分浏览器都支持 WebSocket() 接口,所以就直接写了
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>WebSocket聊天室</title> </head> <body> <div id="main" style="width:600px;height: 200px; overflow: auto;border: solid 2px black;"> </div> <textarea id="textarea"></textarea> <br/> <input type="button" value="发送数据" onclick="send()"> <script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script type="text/javascript"> var name =prompt("请输入您的昵称","匿名者"); //弹出input框 // 打开一个 web socket var ws = new WebSocket("ws://118.25.224.221:9501"); ws.onopen = function() { console.log("连接成功"); }; //收到消息 触发回调 ws.onmessage = function (evt) { var data = evt.data; console.log("收到socket服务消息,内容:" + data); $('#main').append("<p>" + data + "</p>"); }; function send() { var data = document.getElementById('textarea').value; ws.send(name+ ":"+ data); } ws.onclose = function() { // 关闭 websocket console.log("连接已关闭..."); }; </script> </body> </html>
也可以看看GoEasy文库的其他资料。