在之前的版本中,可能会出现这样的情况,在WebSocket服务端,在close事件回调中无法区分fd是否为WebSocket连接,比如下面的代码://创建一个WebSocketServer对象,监听0.0.0.0:9501端口$ws=newSwoole\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}isclosed\n";});$ws->start();启动服务后,使用浏览器向127.0.0.1:9501发起请求,终端会得到输出:client-1isclosed[2021-05-2416:58:08*37715.1]NOTICEend(ERRNO1005):session[1]outputlikeisclosed不知道$fd为1的连接是否是WebSocket连接。在业务代码中直接使用$fd做一些逻辑处理是没有用的,而且可能存在恶意请求导致资源被占用。那么熟悉Swoole开发的人就会想到加判断:利用getClientInfo方法的websocket_status值获取WebSocket连接状态。当服务器为WebSocket\Server时,getClientInfo会额外添加websocket_status信息,对应的状态有四种,为常量对应值说明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}已关闭,WebSocket状态为{$is_websocket}\n";}else{echo"client-{$fd}不是有效的WebSocket连接\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-1iscloseed,WebSocketstatusis3client-2isnotavalidWebSocketconnection现在从v4.7.0版本开始,增加了一个onDisconnect事件回调,在上面的代码中加入://监听WebSocket错误连接关闭事件$ws->on('Disconnect',function($ws,$fd){echo"client-{$fd}isDisconnect\n";});重启服务器,发起请求,得到:client-1isclosed,WebSocket状态为3client-2is这样,Disconnect可以直接区分是否为WebSocket连接WebSocket\Server建立连接。OnDisconnect事件回调,非WebSocket请求或者在onRequest中调用$response->close()方法,都会回调onDisconnect。onClose或onDisconnect事件不会在onRequest事件中正常结束时被调用。反之,如果没有设置onDisconnect事件回调,非WebSocket请求会调用onClose回调或者在onRequest中调用$response->close()方法。
