在之前的版本中可能有这样一种情况,在 WebSocket 服务器中无法在 close 事件回调中区分该 fd
是否为 WebSocket 连接,例如以下代码:
//创建WebSocket Server对象,监听0.0.0.0:9501端口
$ws = new Swoole\WebSocket\Server('0.0.0.0', 9501);
//监听WebSocket连接打开事件
$ws->on('Open', function ($ws, $request) {
$ws->push($request->fd, "hello, welcome\n");
});
//监听WebSocket消息事件
$ws->on('Message', function ($ws, $frame) {
echo "Message: {$frame->data}\n";
$ws->push($frame->fd, "server: {$frame->data}");
});
//监听WebSocket连接关闭事件
$ws->on('Close', function ($ws, $fd) {
echo "client-{$fd} is closed\n";
});
$ws->start();
启动服务后,使用浏览器对127.0.0.1:9501
发起请求,终端会得到输出:
client-1 is closed
[2021-05-24 16:58:08 *37715.1] NOTICE end (ERRNO 1005): session[1] is closed
这样的输出并不能知道这个$fd
为1
的连接是否为 WebSocket 连接。如果业务代码中存在直接使用该$fd
去做一些逻辑处理是无用的,也有可能会发生有人恶意请求导致占用资源。
那么熟悉 Swoole 开发的人就会想到可以增加判断:使用 getClientInfo 方法的websocket_status
值来获取 WebSocket 连接状态
当服务器是 WebSocket\Server
时, getClientInfo
会额外增加websocket_status
信息,它有对应的 4 种状态,分别为
常量 | 对应值 | 说明 |
---|---|---|
WEBSOCKET_STATUS_CONNECTION | 1 | 连接进入等待握手 |
WEBSOCKET_STATUS_HANDSHAKE | 2 | 正在握手 |
WEBSOCKET_STATUS_ACTIVE | 3 | 已握手成功等待浏览器发送数据帧 |
WEBSOCKET_STATUS_CLOSING | 4 | 连接正在进行关闭握手,即将关闭 |
可以修改上述代码中的 onClose
回调:
$ws->on('Close', function ($ws, $fd) {
$is_websocket = $ws->getClientInfo($fd)['websocket_status'];
if ($is_websocket) {
echo "client-{$fd} is closed, WebSocket status is {$is_websocket}\n";
} else {
echo "client-{$fd} is not a valid WebSocket connection\n";
}
});
WebSocket\Server
还可以设置onRequest
回调,同理增加:
$ws->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) {
if (isset($request->get['close'])) {
$response->close();
}
});
重启服务器,分别使用 WebSocket 客户端来请求后关闭和浏览器请求 http://127.0.0.1:9501/?close=1
后会得到这样的输出:
client-1 is closed, WebSocket status is 3
client-2 is not a valid WebSocket connection
现在从 v4.7.0
版本开始,增加了 onDisconnect
事件回调,在上述代码中增加:
//监听WebSocket错误的连接关闭事件
$ws->on('Disconnect', function ($ws, $fd) {
echo "client-{$fd} is Disconnect\n";
});
重启服务器,发起请求会得到:
client-1 is closed, WebSocket status is 3
client-2 is Disconnect
这样就可以直接来区分连接是否为 WebSocket 连接。
WebSocket\Server
设置了 onDisconnect
事件回调,非 WebSocket 请求或者在 onRequest
调用 $response->close()
方法,都会回调onDisconnect
。而在 onRequest
事件中正常结束则不会调用onClose
或onDisconnect
事件。
反之,如果不设置 onDisconnect
事件回调,非 WebSocket 请求或者在 onRequest
调用 $response->close()
方法,则都会调用onClose
回调。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。