Latticework

Command Palette

Search for a command to run...

WebSockets

Message Framing

20 min

Explanation

TCP delivers a raw stream of bytes with no built-in concept of "where one message ends." WebSocket solves this with explicit frames: each message is wrapped in a small header that says (among other things) how long the payload is, so the receiver knows exactly where to stop reading. The first header byte packs two things into one byte: the top bit is FIN (is this the final frame of the message?), and the bottom 4 bits are the opcode (0x1 = text, 0x2 = binary, 0x8 = close).

def encode_frame(payload):
    header = bytearray()
    header.append(0x81)          # FIN=1, opcode=1 (text) packed into one byte
    length = len(payload)
    if length < 126:
        header.append(length)     # small payloads: length fits directly in byte 1
    return bytes(header) + payload
Try it

0x81 is 10000001 in binary -- the leading 1 is FIN, and 0001 is the text opcode. Real frames also need a masking bit (client-to-server frames MUST be masked with a random key per RFC 6455, server-to-client frames must NOT be) -- this simplified version only covers the unmasked server-to-client case.

Loading editor…
Exercise

Write `encode_frame(payload)`: build a minimal WebSocket text frame header for a small (< 126 byte), unmasked, single-frame payload — byte 0 is `0x81` (FIN=1, opcode=1 for text), byte 1 is the payload length. Return the header bytes concatenated with `payload`.

Quiz

Unlike HTTP, WebSocket doesn't send messages as plain, self-delimited text. Why does it need explicit frame headers at all?

Checkpoint

You can build a minimal WebSocket frame header and understand why explicit framing is necessary on top of TCP's raw byte stream.