websocketspring-websockettyrussocketrocket

Why do client websocket close codes not match the server code?


I have a Spring Boot Tomcat server that is handling websocket connections from clients that are using:

  1. SocketRocket
  2. Tyrus

I find that the close code provided by the server is often not the close code read by the client.

For SocketRocket, I close the websocket at the server with code 1000, and the client often reads 1001.

For Tyrus, I close the websocket with code 1011, and the client reads either 1006 or 1011.

Descriptions of close codes from RFC 6455:

1000 indicates a normal closure, meaning that the purpose for which the connection was established has been fulfilled.

1001 indicates that an endpoint is "going away", such as a server going down or a browser having navigated away from a page.

1006 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting a status code to indicate that the connection was closed abnormally, e.g., without sending or receiving a Close control frame.

1011 indicates that a server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.

I have verified the outgoing close codes using Wireshark at the server.

Is the close code just unreliable as a means of passing information from the server to the client? Do I need to implement something at the application layer that passes this information before closing websockets?


Solution

  • This is just a guess, but the WebSocket clients you listed may not implement the closing handshake correctly.

    Why don't you try nv-websocket-client to see what's happening? onDisconnected method of the library's listener interface (WebSocketListener) is defined as below.

    void onDisconnected(
            WebSocket websocket,
            WebSocketFrame serverCloseFrame,
            WebSocketFrame clientCloseFrame,
            boolean closedByServer);
    

    The second argument serverCloseFrame is the close frame which the server sent to the client, and the third argument clientCloseFrame is the close frame which the client sent to the server. In normal cases, as required by the specification, payloads of the two close frames are identical.