首页
下载
文档
问答社区
视频
捐赠
源代码
AI 助理
赞助商
CRMEB
Apipost
腾讯云
微擎
禅道
51Talk
商业产品
Swoole AI 智能文档翻译器
Swoole-Compiler PHP 代码加密器
CRMEB 新零售社交电商系统
登录
注册
全部
提问
分享
讨论
建议
公告
开发框架
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`回调。 ![](https://cdn.jsdelivr.net/gh/sy-records/staticfile/images/swoole/wechat.png)
发布于3年前 · 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`回调。 ![](https://cdn.jsdelivr.net/gh/sy-records/staticfile/images/swoole/wechat.png)
赞
0
分享
收藏
提问
分享
讨论
建议
公告
开发框架
CodeGalaxy
评论
还没有评论!
微信公众号
热门内容
作者其它话题
- thinkphp5.1在使用think-swoole的时候报错unsupported option [host]
- WSL 下服务器响应数据过大无法接收
暂无回复的问答
- CodeGalaxy K3s 轻量集群节点之间如何实现负载均衡
- 关于openssl CURL WARNING swSSL_connect: SSL_connect(fd=69) failed. Error: error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small[1|394]
- 多个模型如何进行事务异常回退?
- websocket开启wss报错
- 协程tcp服务器如何使用多进程?recv()方法接收信息,打印出来的pid一直是同一个。没用使用到多进程啊。