Swoole v4.7 features a preview of onDisconnect event callback.

In previous versions there might have been a case where the WebSocket server could not tell whether the FD was a WebSocket connection in the close event callback, as in the following code:

// Create a WebSocket Server object that listens on port 0.0.0.0:9501
$ws = new Swoole\WebSocket\Server('0.0.0.0'.9501);

// Listen for WebSocket connection opening events
$ws->on('Open'.function ($ws.$request) {
    $ws->push($request->fd, "hello, welcome\n");
});

// Listen for WebSocket message events
$ws->on('Message'.function ($ws.$frame) {
    echo "Message: {$frame->data}\n";
    $ws->push($frame->fd, "server: {$frame->data}");
});

// Listen for WebSocket connection closure events
$ws->on('Close'.function ($ws.$fd) {
    echo "client-{$fd} is closed\n";
});

$ws->start();
Copy the code

After starting the service, use a browser to request 127.0.0.1:9501 and the terminal will get the following output:

Client-1 is closed [2021-05-24 16:58:08 *37715.1] NOTICE End (ERRNO 1005): Session [1] is closedCopy the code

This output does not tell whether the connection with $fd of 1 is a WebSocket connection. If there is something in the business code that uses the $fd directly to do some logical processing that is useless, there is also the possibility that someone will make a malicious request and cause the resource to be occupied.

Those familiar with Swoole’s development can then think of an added judgment: use the websocket_status value of the getClientInfo method to retrieve the WebSocket connection status

When the Server is WebSocket\Server, getClientInfo will add webSocket_status information, which has four corresponding states, respectively

constant The corresponding value instructions
WEBSOCKET_STATUS_CONNECTION 1 Connect into waiting handshake
WEBSOCKET_STATUS_HANDSHAKE 2 Is to shake hands
WEBSOCKET_STATUS_ACTIVE 3 The handshake is successful and the browser is waiting to send the data frame
WEBSOCKET_STATUS_CLOSING 4 Connection closing handshake in progress, about to close

You can modify the onClose callback in the above code:

$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"; }});Copy the code

WebSocket\Server can also set the onRequest callback, similarly added:

$ws->on('request'.function (Swoole\Http\Request $request, Swoole\Http\Response $response) {
    if (isset($request->get['close']) {$response->close(); }});Copy the code

Restart the server, use WebSocket client respectively to request after closing and browser request http://127.0.0.1:9501/? Close =1 gives this output:

client-1 is closed, WebSocket status is 3
client-2 is not a valid WebSocket connection
Copy the code

Now starting with v4.7.0, the onDisconnect event callback has been added to the code above:

// Listen for WebSocket error connection closure events
$ws->on('Disconnect'.function ($ws.$fd) {
    echo "client-{$fd} is Disconnect\n";
});
Copy the code

Restart the server and make a request to get:

client-1 is closed, WebSocket status is 3
client-2 is Disconnect
Copy the code

This allows you to directly distinguish whether a connection is a WebSocket connection.

WebSocket\Server sets the onDisconnect event callback. OnDisconnect will be called either on a non-websocket request or by calling the $Response ->close() method on onRequest. The onClose or onDisconnect events will not be called if the onRequest event ends normally.

Conversely, the onClose callback is called if the onDisconnect event callback is not set, non-websocket requests, or if the $Response ->close() method is called on onRequest.