On this page
Binary Protocol Design
Binary protocols are more compact than text protocols, but every design decision—framing (length-prefixed vs delimiter), integer encoding (varint vs fixed), extensibility (TLV allows parsers to skip unknown fields)—affects the protocol’s bandwidth efficiency, parsing complexity, and forward compatibility. Protobuf’s wire format is a classic reference for these decisions.
Overview
Binary protocols are more compact than text protocols, but require careful design of field encoding and extensibility. Core decisions: framing method (length-prefixed vs delimiter), integer encoding (varint vs fixed-width), extensibility (TLV allows parsers to skip unknown fields). Protobuf (Google, 2008) is widely used for microservice communication and configuration serialization; its wire format design—field number + wire type tag + varint/length-delimited data—is an excellent example of binary protocol design.
Framing
Length-prefixed:
[4-byte len (big-endian)][payload]
Pros: Simple, read len → allocate buffer → read payload
Cons: Requires knowing the length in advance
Delimiter-based:
[payload][CR LF CR LF] ← HTTP header boundary
[payload][CR LF . CR LF] ← SMTP body end
→ Requires escaping when delimiter appears in payload
TLV (Type-Length-Value)
Extensibility: if the parser doesn't recognize the type → skip by length → forward compatible
[Type (1-2B)] [Length (1-4B)] [Value (length bytes)]
Integer Encoding
Fixed: 2/4/8B big-endian (IP, TCP, DNS)
varint (protobuf, QUIC):
Highest bit of each byte = "more bytes follow"
Example: 300 = 0x12C → 1010 1100 0000 0010 = AC 02 (2B)
ZigZag (signed int):
sint32: 0→0, -1→1, 1→2, -2→3 → smaller encoding for small absolute values
Protobuf Wire Format
field = (field_number << 3) | wire_type
wire_type: 0=varint, 2=length-delimited
message Person {
string name = 1; → tag: 0x0A (1<<3 | 2), len, UTF-8 bytes
int32 age = 2; → tag: 0x10 (2<<3 | 0), varint
}
Byte Order
Big-endian (network byte order): TCP/IP headers → htons() / htonl()
Little-endian (host): x86/ARM → new protocols use LE (CPU native, fewer conversions)
References
- protobuf: protobuf.dev/programming-guides/encoding
- QUIC: RFC 9000 (varint encoding in Appendix A)
Keywords: framing, TLV, varint, protobuf, big-endian, little-endian, ZigZag