Step 1 of 3 · Reading · ~3 min
The Real RESP Wire Protocol
RESP Protocol Fundamentals
RESP Array Parsing — The Real Wire Protocol
Everything up to now has used a shortcut: space-separated text commands. That was fine for learning RESP replies, but it is not how any real Redis client — redis-cli, redis-py, ioredis — actually talks to a server. Real clients send requests as RESP arrays of bulk strings. This lesson replaces your toy line parser with the real thing.
Why space-splitting breaks
Space-separated parsing cannot represent a value that itself contains a space, a newline, or arbitrary binary bytes (image data, serialized objects, etc.). SET note "hello world" is already ambiguous with naive splitting. Real Redis sidesteps this entirely by never guessing where a value ends — every piece of data is prefixed with its exact byte length.
The RESP array format
A client request is encoded as:
*<N>\r\n
$<len1>\r\n<arg1>\r\n
$<len2>\r\n<arg2>\r\n
...
$<lenN>\r\n<argN>\r\n
SET foo bar becomes:
*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n
Read it as: "an array of 3 elements, first element is a 3-byte bulk string SET, second is a 3-byte bulk string foo, third is a 3-byte bulk string bar."
Writing a binary-safe parser
The key discipline: never split on whitespace or newlines to find where a bulk string ends — trust the length prefix. Read exactly len bytes, then consume the trailing \r\n unconditionally.
Note that read_line is only ever used for the headers (*N and $len), which are guaranteed to be plain ASCII digits with no embedded CRLF. The payload itself is read with a fixed-size read(length), never scanned for delimiters — that's what makes it binary-safe.
Wiring it into your dispatcher
Once parsed, args[0] is your command name and args[1:] are its arguments — feed them into the same HANDLERS dispatch table you already built for PING/ECHO/etc. Nothing about command execution changes; only how you get from "bytes on the wire" to "a list of strings" changes.
Edge cases
- Empty arrays (
*0\r\n) should probably be ignored or produce no reply, mirroring how the passive-connection keepalive works in real Redis. - Argument values may be empty strings (
$0\r\n\r\n) — that's valid and different from null ($-1\r\n). - Don't assume the whole request arrives in one
read()call if you're working over a real socket later — for now, with a buffered stdin stream, reading byte-by-byte (or line-by-line for headers) keeps things correct even if not maximally fast.
This parser is the real foundation the rest of the course builds on: every future command — lists, hashes, transactions, pub/sub — arrives as exactly this array-of-bulk-strings shape.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…