Swoole v4.7 版本新特性预览之 onDisconnect 事件回调

二进制诗人
• 阅读 2787

在之前的版本中可能有这样一种情况,在 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

这样的输出并不能知道这个$fd1的连接是否为 WebSocket 连接。如果业务代码中存在直接使用该$fd去做一些逻辑处理是无用的,也有可能会发生有人恶意请求导致占用资源。

那么熟悉 Swoole 开发的人就会想到可以增加判断:使用 getClientInfo 方法的websocket_status值来获取 WebSocket 连接状态

当服务器是 WebSocket\Server 时, getClientInfo 会额外增加websocket_status信息,它有对应的 4 种状态,分别为

常量对应值说明
WEBSOCKET_STATUS_CONNECTION1连接进入等待握手
WEBSOCKET_STATUS_HANDSHAKE2正在握手
WEBSOCKET_STATUS_ACTIVE3已握手成功等待浏览器发送数据帧
WEBSOCKET_STATUS_CLOSING4连接正在进行关闭握手,即将关闭

可以修改上述代码中的 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 事件中正常结束则不会调用onCloseonDisconnect事件。

反之,如果不设置 onDisconnect 事件回调,非 WebSocket 请求或者在 onRequest 调用 $response->close() 方法,则都会调用onClose回调。

Swoole v4.7 版本新特性预览之 onDisconnect 事件回调

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
3年前
java中比较两个时间的差值
项目背景1.某篇文稿的发布时间是publishDate,例如:2020072118:00:41。2.现要求判断该篇文稿的发布时间是否在近30天之内。publicstaticlongdayDiff(DatecurrentDate,DatepublishDate){LongcurrentTimecurrentDat
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Cocos Creator中使用事件中心
exportclassEventCenter{/监听数组/privatelisteners{};/注册事件@paramname事件名称@paramcallback回调函数
Wesley13 Wesley13
3年前
IOS拦截重定向请求(302)的几种方式
前言在多数情况下,我们做的网络请求是返回200状态码的,但也有返回302的时候,比如使用基于Oauth2认证协议的API时,在认证阶段,需要提供一个回调地址,当用户授权后,服务器会返回一个302Response,ResponseHeader中会一个Location字段,包含了我们的回调地址,同时会有一个Code参数。我们在程序中该如何处理这个
Wesley13 Wesley13
3年前
Java Web(九)
Listener&FilterListener  监听器1、能做什么事?  监听某一个事件的发生。状态的改变。2、监听器的内部机制  其实就是接口回调.接口回调1、需求:  A在执行循环,当循环到5的时候,通知B。 
Stella981 Stella981
3年前
JavaScript回调函数的高手指南
摘要:本文将会解释回调函数的概念,同时帮你区分两种回调:同步和异步。回调函数是每个前端程序员都应该知道的概念之一。回调可用于数组、计时器函数、promise、事件处理中。本文将会解释回调函数的概念,同时帮你区分两种回调:同步和异步。1.回调函数首先写一个向人打招呼的函数。只需要创建一个接受name参数的函数gree
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable