Principles and Implementation of Dependency Injection and Inversion of Control (IoC) Containers (Repeated title, already covered)
Principles and Implementation of the WebSocket Protocol
Description
WebSocket is a protocol for full-duplex communication over a single TCP connection, allowing both the server and client to actively push data to each other, thereby avoiding the overhead of HTTP polling. Its core principle involves establishing a persistent connection via an HTTP upgrade request and then transmitting data in Frame format. Mastering the implementation mechanism of WebSocket is crucial for building real-time applications (such as chat systems, online games).
Problem-Solving Process
-
Handshake Phase
- Client Request: The client sends an HTTP upgrade request containing the following header fields:
GET /chat HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== # Randomly generated 16-byte Base64 encoded string Sec-WebSocket-Version: 13 - Server Response: After validating the request, the server returns status code 101 (Switching Protocols) and generates a response key:
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= # Calculated based on the client's Key- Calculation method: Concatenate the client's
Sec-WebSocket-Keywith the fixed GUID"258EAFA5-E914-47DA-95CA-C5AB0DC85B11", perform SHA-1 hashing, and finally Base64 encode the result.
- Calculation method: Concatenate the client's
- Client Request: The client sends an HTTP upgrade request containing the following header fields:
-
Data Frame Format (Frame Protocol)
After a successful handshake, both parties communicate via binary frames. The format of a frame is as follows (unit: bits):0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-------+-+-------------+-------------------------------+ |F|R|R|R| opcode|M| Payload Len | Extended Payload Length | |I|S|S|S| (4) |A| (7) | (16/64) | |N|V|V|V| |S| | (if payload len==126/127) | | |1|2|3| |K| | | +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + | Extended Payload Length continued, if payload len == 127 | + - - - - - - - - - - - - - - - +-------------------------------+ | |Masking-key, if MASK set to 1 | +-------------------------------+-------------------------------+ | Masking-key (continued) | Payload Data | +-------------------------------- - - - - - - - - - - - - - - - + : Payload Data continued ... : + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | Payload Data continued ... | +---------------------------------------------------------------+- Key Fields:
FIN(1 bit): Indicates whether this is the final frame of a message.opcode(4 bits): Frame type (e.g., 1=text, 2=binary, 8=close connection).MASK(1 bit): Frames sent from client to server must be masked (frames from server to client do not require masking).Payload Len(7 bits): Data length. If length ≥ 126, subsequent extended bytes represent the actual length.Masking-key(4 bytes): Exists only when MASK=1, used to decode the payload data.
- Key Fields:
-
Mask Decoding and Encoding
- Client Sending: Data must be encoded using XOR with the
Masking-key. Decoding formula:decoded[i] = payload[i] XOR masking_key[i % 4] - Server Sending: No masking required; raw data is sent directly.
- Client Sending: Data must be encoded using XOR with the
-
Implementation Key Points
- Server Example (Pseudocode):
# 1. Handshake Response def handle_handshake(request): key = request.headers['Sec-WebSocket-Key'] accept_key = base64encode(sha1(key + GUID)) response = f"HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: {accept_key}\r\n\r\n" socket.send(response) # 2. Parse Frame def parse_frame(data): fin = (data[0] & 0x80) == 0x80 opcode = data[0] & 0x0F masked = (data[1] & 0x80) == 0x80 payload_len = data[1] & 0x7F offset = 2 if payload_len == 126: payload_len = (data[2] << 8) + data[3] offset += 2 elif payload_len == 127: payload_len = ... # Handle 64-bit length offset += 8 if masked: masking_key = data[offset:offset+4] offset += 4 payload = data[offset:offset+payload_len] # Apply mask decoding decoded = bytearray(payload[i] ^ masking_key[i % 4] for i in range(len(payload))) return decoded - Heartbeat Mechanism (Ping/Pong): Keep the connection alive using opcode 9 (Ping) and 10 (Pong).
- Server Example (Pseudocode):
-
Application Scenarios
- Real-time message推送 (e.g., chat rooms, notification systems).
- Multiplayer online games, collaborative editing tools.
- Real-time financial market data updates.
Summary
WebSocket achieves efficient bidirectional communication through a lightweight frame protocol, avoiding the latency of HTTP polling. Understanding its handshake process, frame structure, and masking mechanism is fundamental to implementing custom WebSocket services or debugging real-time applications.