As I mentioned here, the WebSockets protocol is, at this point, a bit of a mess due to the evolution of the protocol and the fact that it’s being pulled in various directions by various interested parties. I’m just ranting about some of the things that I find annoying…
The WebSockets protocol includes a way for the endpoints to shut down the connection.
If an endpoint receives a Close frame and that endpoint did not previously send a Close frame, the endpoint MUST send a Close frame in response. It SHOULD do so as soon as is practical. An endpoint MAY delay sending a close frame until its current message is sent (for instance, if the majority of a fragmented message is already sent, an endpoint MAY send the remaining fragments before sending a Close frame). However, there is no guarantee that the endpoint which has already sent a Close frame will continue to process data.
After both sending and receiving a close message, an endpoint considers the WebSocket connection closed, and MUST close the underlying TCP connection. The server MUST close the underlying TCP connection immediately; the client SHOULD wait for the server to close the connection but MAY close the connection at any time after sending and receiving a close message, e.g. if it has not received a TCP close from the server in a reasonable time period.
Unfortunately it’s a full close of the connection in both directions rather than an indication that the endpoint sending it has nothing more to send. In effect it’s a
close() rather than a
shutdown(). This means that if you ever want to indicate that you’re done sending but that you’d like the other end to finish up and then close you have to implement it yourself…
TCP allows you to close each direction of the connection independently. The first peer to shut down their sending side is deemed to have issued the active close. Whoever issues the active close ends up in
TIME_WAIT state (see here for more details on that). The WebSockets protocol provides a protocol level close message which is intended to do the following:
The closing handshake is intended to complement the TCP closing handshake (FIN/ACK), on the basis that the TCP closing handshake is not always reliable end-to-end, especially in the presence of man-in- the-middle proxies and other intermediaries.
By sending a close frame and waiting for a close frame in response, certain cases are avoided where data may be unnecessarily lost. For instance, on some platforms, if a socket is closed with data in the receive queue, a RST packet is sent, which will then cause recv() to fail for the party that received the RST, even if there was data waiting to be read.
Which is all well and good but the ability to perform a half-close would be very useful and its unfortunate omission will no doubt lead to applications inventing their own…