In a WebSocket data frame, what do the FIN bit and the 4-bit opcode in the first byte tell the receiver?
answer
- first byte, four fields
- one bit for the message end
- low four bits name the frame
- RSV bits zero without an extension
- 0x81 is FIN plus opcode %x1
basics
~20 sFIN says whether this frame is the last of its message; the 4-bit opcode says what the frame is: %x0 continuation, %x1 text, %x2 binary, %x8 close, %x9 ping, %xA pong. Three RSV bits sit between them.
solid answer
~40 sEvery WebSocket frame starts with one byte holding four things. Bit 7 is `FIN`: set means this frame completes the message, clear means more frames follow. Bits 6-4 are `RSV1`, `RSV2` and `RSV3`, which must be zero unless a negotiated extension gives them meaning. The low four bits are the opcode: `%x0` continuation, `%x1` text, `%x2` binary, `%x8` close, `%x9` ping, `%xA` pong, with `%x3`-`%x7` reserved for future data frames and `%xB`-`%xF` for future control frames. So `0x81` reads as FIN set, no RSV, opcode `%x1` — one complete text frame. Opcodes `%x8` and above are control frames and follow stricter rules than data frames.
code
http · 5 lines81 05 48 65 6c 6c 6f
# 0x81 = 1000 0001 -> FIN=1, RSV1..3=0, opcode=%x1 (text)
# 0x05 = 0000 0101 -> MASK=0, payload length 5
# 48 65 6c 6c 6f -> the five payload bytesgo deeper
Memorise the six named opcodes and what FIN means: %x0 continuation, %x1 text, %x2 binary, %x8 close, %x9 ping, %xA pong, and FIN = last frame of this message.
Explain why the opcode's high bit separates control frames from data frames, and why an RSV bit set with no negotiated extension is a protocol error rather than something to ignore.
Be able to read a capture: identify a frame from its first byte, spot a fragmented message in progress, and explain what the header deliberately omits — no id, no channel, no length in that byte.
The judgment call is what the application must add on top: with no message id and no channel in the header, request/reply pairing and multiplexing are conventions your team defines and every client must share.
## One byte, four fields A WebSocket frame is not a text protocol and has no delimiter you can grep for. It opens with a fixed two-byte header, and the **first byte** alone carries four separate pieces of information packed into single bits and one nibble: | bits | field | meaning | |---|---|---| | bit 7 | `FIN` | 1 = this frame is the final frame of its message; 0 = more frames follow | | bit 6 | `RSV1` | reserved; 0 unless a negotiated extension defines it | | bit 5 | `RSV2` | reserved; 0 unless a negotiated extension defines it | | bit 4 | `RSV3` | reserved; 0 unless a negotiated extension defines it | | bits 3-0 | opcode | what kind of frame this is | The second byte carries the `MASK` bit and the payload length, which are a separate subject. Everything below concerns the first byte only. ## FIN marks a message boundary, not a connection end This is the most common first misreading. `FIN` set does **not** mean the connection is finishing; it means *this message* is finished. A WebSocket connection carries an unbounded sequence of messages, and each message is one or more frames. The overwhelmingly common case — a short command sent whole — is a single frame with `FIN` set. When a sender chooses to split a message, only the last frame of that message has `FIN` set. Note how little that costs: a sender that has not yet computed the total size of what it is sending can emit a first frame with `FIN` clear and keep appending, because the message's end is signalled by a bit on the *last* frame rather than by a length declared up front. ## The opcode nibble Four bits give sixteen values. The specification assigns six and reserves the rest: - **`%x0` continuation** — this frame carries more of a message that an earlier frame began. - **`%x1` text** — the payload is UTF-8 encoded text. - **`%x2` binary** — the payload is arbitrary bytes. - **`%x3`-`%x7`** — reserved for further **non-control** (data) frames. - **`%x8` close** — the connection-close control frame. - **`%x9` ping** — a liveness probe control frame. - **`%xA` pong** — the answer to a ping. - **`%xB`-`%xF`** — reserved for further **control** frames. The split is not arbitrary: the **high bit of the opcode** separates the two classes. Opcodes `%x0`-`%x7` are data frames; `%x8`-`%xF` are control frames. A receiver can therefore decide, from four bits, whether it is holding application payload or protocol machinery — before it has looked at a single byte of the body. Receiving a reserved opcode that no extension has defined is a protocol error, and the endpoint fails the connection rather than guessing. ## The RSV bits and why they are usually zero `RSV1`, `RSV2` and `RSV3` exist so that a negotiated extension can add per-frame signalling without a new frame format. If no extension was agreed when the connection opened, all three **must** be zero, and an endpoint that receives a frame with one of them set on a connection where nothing defines it treats that as a protocol error and fails the connection (the close status for a protocol error is 1002). The rule is strict on purpose: a receiver that quietly ignored a reserved bit would silently mis-deliver payload that an extension had transformed. ## Reading it off the wire A complete, unmasked text frame carrying five bytes looks like this: ```http 81 05 48 65 6c 6c 6f ``` `0x81` is `1000 0001`: `FIN` set, all three RSV bits clear, opcode `%x1`. `0x05` is the length. The remaining five bytes are the payload. Change the first byte to `0x01` and the same bytes become the *opening* fragment of a longer text message; change it to `0x89` and it becomes a ping, which is a control frame and obeys a tighter size rule. ## What the first byte does not tell you It is worth being precise about the absences, because interviewers probe them: 1. **No message identifier.** A WebSocket frame carries no sequence number and no correlation id. If an application needs to pair a reply with a request, it invents that field itself inside the payload. 2. **No length.** The length lives in the second byte and possibly in two or eight bytes after it. 3. **No direction or channel.** Nothing in the byte says who sent it or which logical stream it belongs to; the connection is the channel. Knowing which facts the header supplies, and which the application must supply for itself, is the whole point of the question.
- Which opcodes are control frames, and how does a receiver tell without a lookup table?`%x8` close, `%x9` ping and `%xA` pong are the defined control frames, and `%xB`-`%xF` are reserved for more. The test is the opcode's high bit: values `%x8` and above are control frames, `%x0`-`%x7` are data frames. That one-bit test lets a receiver route a frame before reading its payload.
- A frame arrives with RSV1 set and no extension was negotiated. What should the endpoint do?Fail the connection. An RSV bit only has meaning when a negotiated extension defines it; set with nothing to define it, it is a protocol error, and the matching close status code is 1002. Ignoring the bit would risk delivering payload that an extension had transformed as if it were untransformed.
- Does FIN set mean the connection is closing?No. `FIN` ends a *message*, not the connection, and the ordinary case — a single-frame message — has `FIN` set on every frame. A connection ends through the close control frame, opcode `%x8`, which is an entirely separate mechanism.
saying these in an interview costs you the question
- Thinks FIN set means the connection is about to close
- Believes the opcode names a channel or a message id
- Thinks text and binary frames use different header layouts
- Assumes RSV bits can be set freely because they are reserved
- Cannot tell a control frame from a data frame by its opcode