WebSocket is a communication protocol that enables full-duplex, bi-directional communication between a client and a server over a single, persistent connection built on top of TCP. Unlike the request-response model that defines regular HTTP traffic, where the client must always initiate every exchange and the server can only reply when asked, WebSocket keeps the connection open once it is established, so either side, the client or the server, can send data to the other at any moment, without waiting for a request first.
Before going further, it helps to be clear on what full-duplex actually means, since it is easiest to understand next to its two relatives: simplex and half-duplex. All three describe the direction data is allowed to flow between two devices that are communicating with each other.
Simplex communication only allows data to move in one direction, from a sender to a receiver, and never the other way. Think of a keyboard or a mouse sending input to a computer. The keyboard tells the computer what key was pressed, but the computer never sends anything back to the keyboard through that same channel. Data flows one way, permanently.
Half-duplex communication allows data to move in both directions, but never at the same time. Only one side can send at any given moment, and the other side has to wait its turn. A walkie-talkie conversation is the clearest everyday example of this. When one person is speaking, the other person has to stay quiet and listen, and only after the first person finishes and signals that they are done, usually by saying something like "over," can the second person start talking. Both sides can send and receive, but taking turns is mandatory.
Full-duplex communication allows data to move in both directions at the same time, with neither side needing to wait for the other. A regular phone call is the clearest example of this. Both people on the call can speak and listen at once, and if you interrupt the other person mid-sentence, they still hear you, because both directions of the conversation are open simultaneously. This is exactly the behavior WebSocket gives to a client and a server. Once the connection is open, the server does not have to wait for the client to ask before sending data, and the client does not have to wait for the server to finish before sending its own message. Both sides can talk over the same open connection whenever they need to.
WebSocket came about as a direct answer to the limitations already discussed with HTTP-based workarounds like polling, long polling, and HTTP streaming in the first series. The design intent was to give developers something closer to raw TCP itself, a connection where data can flow freely in both directions with minimal overhead. At the same time, they could not hand developers pure, unmodified TCP, because TCP on its own knows nothing about how the web works. It has no concept of an HTTP-based origin, no built-in way to distinguish one message from another, and no knowledge of the security assumptions browsers already rely on. So WebSocket layers a small number of abstractions on top of TCP, just enough to let it work correctly within the existing web platform, without reintroducing the request-response overhead it was designed to escape.
The WebSocket Protocol
At a high level, the WebSocket protocol has three phases. It begins with an opening handshake, where a regular HTTP connection is upgraded into a WebSocket connection. This is followed by the data transfer phase, where the actual back-and-forth communication happens, with both the client and the server free to send messages whenever they need to, in either direction. Finally, there is a closing handshake, where either side signals that it wants to end the connection, and both sides agree to close it cleanly. Each of these phases is worth walking through in detail, starting with how the opening handshake works.
The Opening Handshake
A WebSocket connection begins life as a normal HTTP request. Browsers, proxies, firewalls, and servers across the internet already understand HTTP and already listen on ports 80 and 443, so a brand new protocol arriving on its own would have nowhere to go. Instead, the client sends an ordinary HTTP GET request with a few extra headers that ask one question: "May we stop speaking HTTP on this connection and speak WebSocket instead?" If the server agrees, it answers with an HTTP response saying so, and from that point the same connection carries WebSocket frames rather than HTTP messages.
Think of a phone call between two people who start out in English. One of them asks, "Can we continue this in French?", the other says yes, and the rest of the call carries on in French over the same line. The line did not drop, but the language changed. Similarly, the TCP connection remains open through the handshake, and only the protocol spoken over it changes.
The Client Request
The request looks like this:
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Version: 13
The Upgrade and Connection headers together are the actual request to switch, they tell the server that the client wants this connection changed over to the WebSocket protocol. The Sec-WebSocket-Key is a random 16-byte value, Base64-encoded, that the client generates fresh for every connection and its job is to make sure the server produces an response that a genuine WebSocket server would know how to produce, which we will see in a moment. The Sec-WebSocket-Version header states the protocol version, and 13 is the only version in use today. The Origin header tells the server which website the request came from, which lets the server refuse connections from pages it does not trust. Browsers add the headers that begin with Sec- themselves, and JavaScript running on a page is not allowed to set them, so a web page cannot forge a WebSocket handshake using ordinary request tools.
The Server Response
If the server accepts, it replies with this:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
The status code 101, Switching Protocols, means "agreed, this connection now speaks something else." The Sec-WebSocket-Accept value is the server's proof that it understood the request, and it is calculated in three steps. The server takes the client's key exactly as it was sent, appends a fixed string defined by the WebSocket standard (258EAFA5-E914-47DA-95CA-C5AB0DC85B11, the same for every WebSocket server), then hashes the result with SHA-1 and Base64-encodes the hash. Applying these steps to the key in the request above produces the value shown in the response. The client repeats the same calculation on its own side and compares the results, and if they match, it knows the server genuinely speaks WebSocket. An ordinary HTTP server, or a cache repeating an old response, would have no reason to produce this value, which is why the check works even though nothing about it is secret.
What the Handshake Achieves
Once the client accepts the response, HTTP is finished on this connection and both sides begin exchanging frames. Three things make a handshake worth doing, instead of simply opening a new kind of connection. First, both sides have confirmed that they understand WebSocket, so a normal HTTP server never mistakes WebSocket frames for a broken HTTP request. Second, because the handshake is an HTTP request, it carries cookies, authorization headers, and the Origin, so the server can check who is connecting and decide whether to accept them before the long-lived connection exists. Third, running over the usual web ports, with wss:// wrapping the handshake in TLS the same way https:// does, lets WebSocket traffic pass through most existing network equipment, although some older proxies still interfere with it.
The payoff shows up in everything that follows. Every message after the handshake travels as a frame whose header can be as small as 2 bytes (up to 10 from the server, and 4 more from the client because of the masking key), while each request in the polling approach from the first series repeated hundreds of bytes of headers and cookies. That gap is a large part of why WebSocket handles frequent messages so much better. With the handshake finished, the connection moves into the second phase of the protocol, data transfer, where everything travels as frames.
Top comments (0)