首页
下载
文档
社区
视频
捐赠
开源项目
typephp
swoole
code-galaxy
swoole-cli
phpx
phpy
赞助商
AOT 编译器
AI 助理
商业产品
Swoole-Compiler 代码加密器
CRMEB 新零售社交电商系统
新加坡独享 Mac mini AI 工作站
登录
注册
全部
提问
分享
讨论
建议
公告
开发框架
TypePHP
CodeGalaxy
发表新帖
Swoole v4.7 版本新特性预览之 onDisconnect 事件回调
在之前的版本中可能有这样一种情况,在 WebSocket 服务器中无法在 close 事件回调中区分该 `fd` 是否为 WebSocket 连接,例如以下代码: ```php //创建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`发起请求,终端会得到输出: ```bash 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](https://wiki.swoole.com/#/server/methods?id=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` 回调: ```php $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`回调,同理增加: ```php $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` 后会得到这样的输出: ```bash client-1 is closed, WebSocket status is 3 client-2 is not a valid WebSocket connection ``` 现在从 `v4.7.0` 版本开始,增加了 `onDisconnect` 事件回调,在上述代码中增加: ```php //监听WebSocket错误的连接关闭事件 $ws->on('Disconnect', function ($ws, $fd) { echo "client-{$fd} is Disconnect\n"; }); ``` 重启服务器,发起请求会得到: ```bash 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`回调。 
发布于5年前 · 19 次浏览 · 来自
分享
鲁飞
在之前的版本中可能有这样一种情况,在 WebSocket 服务器中无法在 close 事件回调中区分该 `fd` 是否为 WebSocket 连接,例如以下代码: ```php //创建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`发起请求,终端会得到输出: ```bash 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](https://wiki.swoole.com/#/server/methods?id=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` 回调: ```php $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`回调,同理增加: ```php $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` 后会得到这样的输出: ```bash client-1 is closed, WebSocket status is 3 client-2 is not a valid WebSocket connection ``` 现在从 `v4.7.0` 版本开始,增加了 `onDisconnect` 事件回调,在上述代码中增加: ```php //监听WebSocket错误的连接关闭事件 $ws->on('Disconnect', function ($ws, $fd) { echo "client-{$fd} is Disconnect\n"; }); ``` 重启服务器,发起请求会得到: ```bash 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`回调。 
赞
0
收藏
提问
分享
讨论
建议
公告
开发框架
TypePHP
CodeGalaxy
登录
后参与评论
评论
还没有评论!