Communication Protocol
This guide describes the VibeMQ message exchange protocol.
Overview
VibeMQ uses TCP as transport and a custom binary format for message serialization. The protocol is designed for simplicity and performance. Payload data is stored as JSON in UTF-8 for easy debugging and UI display, while the protocol message structure uses a compact binary format.
Protocol Layers
┌─────────────────────────────────────┐
│ Application Layer (Binary) │
├─────────────────────────────────────┤
│ Compression (optional, per-frame) │
├─────────────────────────────────────┤
│ Framing (Length-prefix) │
├─────────────────────────────────────┤
│ Transport (TCP) │
└─────────────────────────────────────┘
Framing
Length-prefix approach is used to separate messages in the TCP stream. Each frame is self-contained and carries its own compression information.
Frame Format
[4 bytes: body length in Big Endian uint32] [1 byte: compression flags] [N bytes: body]
body length — size of the (possibly compressed) body in bytes.
compression flags — algorithm identifier (see Compression Flags Byte).
body — serialized (and optionally compressed)
ProtocolMessage.
Compression Flags Byte
Value |
Meaning |
|---|---|
0x00 |
No compression |
0x01 |
GZip |
0x02 |
Brotli |
Frame Example (no compression)
Bytes 0-3: [0x00 0x00 0x00 0x5A] ← Body length: 90 bytes
Byte 4: [0x00] ← No compression
Bytes 5-94: [binary message data] ← Binary protocol message
Frame Example (Brotli)
Bytes 0-3: [0x00 0x00 0x00 0x2C] ← Compressed body length: 44 bytes
Byte 4: [0x02] ← Brotli compression
Bytes 5-48: [compressed data] ← Brotli-compressed binary message
Compression
VibeMQ supports optional frame-level compression using GZip and Brotli (both built in to .NET, no external dependencies). Compression is negotiated during the Connect handshake and applied transparently to all subsequent frames.
Negotiation
The client advertises its preferred algorithms in the Connect message (comma-separated, in descending priority). The server replies with the selected algorithm in ConnectAck. If the server omits the header, no compression is used.
Client → Connect:
{
"headers": {
"supported-compression": "brotli,gzip"
}
}
Server → ConnectAck:
{
"headers": {
"negotiated-compression": "brotli"
}
}
After the handshake, FrameWriter on both sides uses the negotiated algorithm. FrameReader
always reads the compression flag directly from each frame, so mixed-compression streams are
handled correctly without shared state.
Threshold
Compression is applied only when the serialized body reaches the configured threshold
(default 1 024 bytes). Frames below the threshold are sent uncompressed (flags = 0x00).
Configuration
Server (BrokerOptions):
builder.ConfigureFrom(new BrokerOptions {
SupportedCompressions = [CompressionAlgorithm.Brotli, CompressionAlgorithm.GZip],
CompressionThreshold = 1024,
});
Client (ClientOptions):
var options = new ClientOptions {
PreferredCompressions = [CompressionAlgorithm.Brotli, CompressionAlgorithm.GZip],
CompressionThreshold = 1024,
};
// Disable compression entirely
PreferredCompressions = [] // client side
SupportedCompressions = [] // server side
Compression Headers
Header |
Direction |
Description |
|---|---|---|
|
Client → Server (Connect) |
Comma-separated preferred algorithms |
supported-compression | Client → Server (Connect) | Comma-separated preferred algorithms |egotiated-compression`` | Server → Client (ConnectAck)| Selected algorithm; absent if none agreed | +——————————+—————————-+———————————————+
Message Format
Binary Protocol Structure
All protocol messages are serialized in a custom binary format with fixed field order:
version (1 byte) | type (1 byte) | id (2B len + UTF-8) |
queue (2B len + UTF-8) | payload (4B len + UTF-8 JSON) |
headers (2B count + pairs) | errorCode (2B len + UTF-8) |
errorMessage (2B len + UTF-8)
All lengths are encoded as Big Endian. Length 0 means the field is absent/null.
Important: Payload is stored as JSON in UTF-8 for easy debugging and UI display, but the protocol message structure itself uses binary encoding for optimal performance.
Logical Structure
The logical structure of messages (shown as JSON for clarity):
{
"version": 1,
"id": "msg_123",
"type": "publish",
"queue": "notifications",
"payload": {...},
"headers": {...},
"errorCode": null,
"errorMessage": null
}
Message Fields
Field |
Type |
Description |
|---|---|---|
|
string |
Unique identifier |
|
CommandType |
Command type |
|
string? |
Queue name |
|
JsonElement? |
Payload |
|
object? |
Headers |
|
int |
Protocol version (default: 1) |
|
string? |
Error code (for Error) |
|
string? |
Error message |
Command Types (CommandType)
public enum CommandType {
// Connection management
Connect = 0,
ConnectAck = 1,
Disconnect = 2,
// Keep-alive
Ping = 10,
Pong = 11,
// Pub/Sub
Publish = 20,
PublishAck = 21,
Subscribe = 22,
SubscribeAck = 23,
Unsubscribe = 24,
UnsubscribeAck = 25,
Deliver = 26,
// Acknowledgment
Ack = 30,
// Queue management
CreateQueue = 40,
DeleteQueue = 41,
QueueInfo = 42,
ListQueues = 43,
// Errors
Error = 99,
}
Command Descriptions
Connection Management
Connect
Direction: Client → Server
Description: Connection request.
{
"id": "conn_123",
"type": "connect",
"headers": {
"authPassword": "my-secret-password",
"clientVersion": "1.0.0"
}
}
ConnectAck
Direction: Server → Client
Description: Connection acknowledgment.
{
"id": "conn_123",
"type": "connectAck",
"headers": {
"serverVersion": "1.0.0",
"connectionId": "srv_456"
}
}
Disconnect
Direction: Client → Server
Description: Disconnection request.
{
"id": "disc_123",
"type": "disconnect"
}
Keep-alive
Ping
Direction: Client → Server
Description: Connection keep-alive check.
{
"id": "ping_123",
"type": "ping"
}
Pong
Direction: Server → Client
Description: Response to Ping.
{
"id": "ping_123",
"type": "pong"
}
Publish/Subscribe
Publish
Direction: Client → Server
Description: Publish message to queue.
{
"id": "msg_123",
"type": "publish",
"queue": "notifications",
"payload": {
"title": "Hello",
"body": "World"
},
"headers": {
"priority": "high",
"correlationId": "corr_456",
"timestamp": "2026-02-18T10:30:00Z"
}
}
PublishAck
Direction: Server → Client
Description: Publish acknowledgment.
{
"id": "msg_123",
"type": "publishAck",
"headers": {
"messageId": "msg_123",
"queueName": "notifications"
}
}
Subscribe
Direction: Client → Server
Description: Subscribe to queue.
{
"id": "sub_123",
"type": "subscribe",
"queue": "notifications"
}
SubscribeAck
Direction: Server → Client
Description: Subscription acknowledgment.
{
"id": "sub_123",
"type": "subscribeAck",
"headers": {
"queueName": "notifications",
"subscriptionId": "sub_123"
}
}
Unsubscribe
Direction: Client → Server
Description: Unsubscribe from queue.
{
"id": "unsub_123",
"type": "unsubscribe",
"queue": "notifications"
}
UnsubscribeAck
Direction: Server → Client
Description: Unsubscription acknowledgment.
{
"id": "unsub_123",
"type": "unsubscribeAck",
"headers": {
"queueName": "notifications"
}
}
Deliver
Direction: Server → Client
Description: Message delivery to subscriber.
{
"id": "msg_123",
"type": "deliver",
"queue": "notifications",
"payload": {
"title": "Hello",
"body": "World"
},
"headers": {
"priority": "high",
"deliveryAttempts": "1"
}
}
Acknowledgment
Ack
Direction: Client → Server
Description: Message receipt acknowledgment.
{
"id": "ack_123",
"type": "ack",
"headers": {
"messageId": "msg_123"
}
}
Queue Management
CreateQueue
Direction: Client → Server
Description: Create queue.
{
"id": "create_123",
"type": "createQueue",
"queue": "my-queue",
"headers": {
"deliveryMode": "RoundRobin",
"maxQueueSize": "10000",
"messageTtl": "3600000"
}
}
DeleteQueue
Direction: Client → Server
Description: Delete queue.
{
"id": "delete_123",
"type": "deleteQueue",
"queue": "my-queue"
}
QueueInfo
Direction: Client → Server, Server → Client
Description: Queue information request/response.
Request:
{
"id": "info_123",
"type": "queueInfo",
"queue": "my-queue"
}
Response:
{
"id": "info_123",
"type": "queueInfo",
"queue": "my-queue",
"payload": {
"name": "my-queue",
"messageCount": 42,
"subscriberCount": 3,
"deliveryMode": "RoundRobin",
"maxSize": 10000,
"createdAt": "2026-02-18T10:00:00Z"
}
}
ListQueues
Direction: Client → Server, Server → Client
Description: Queue list request/response.
Request:
{
"id": "list_123",
"type": "listQueues"
}
Response:
{
"id": "list_123",
"type": "listQueues",
"payload": ["queue1", "queue2", "queue3"]
}
Errors
Error
Direction: Server → Client
Description: Error message.
{
"id": "err_123",
"type": "error",
"errorCode": "AUTH_FAILED",
"errorMessage": "Invalid username or password"
}
Error Codes
Code |
Description |
|---|---|
|
Authentication error |
|
Invalid message format |
|
Queue not found |
|
Queue already exists |
|
Rate limit exceeded |
|
Internal server error |
Headers
Common Headers
Message Headers
Header |
Description |
|---|---|
|
Priority (Low, Normal, High, Critical) |
|
ID for request correlation |
|
Creation time (ISO 8601) |
|
Number of delivery attempts |
|
Message ID |
|
Queue name |
|
Subscription ID |
Queue Headers
Header |
Description |
|---|---|
|
Delivery mode |
|
Maximum size |
|
TTL in milliseconds |
|
Enable DLQ |
|
Max delivery attempts |
Exchange Examples
Connection Establishment
Client → Server:
{
"id": "conn_001",
"type": "connect",
"headers": {
"authPassword": "my-password",
"supported-compression": "brotli,gzip"
}
}
Server → Client:
{
"id": "conn_001",
"type": "connectAck",
"headers": {
"connectionId": "srv_100",
"negotiated-compression": "brotli"
}
}
Message Publishing
Client → Server:
{
"id": "msg_001",
"type": "publish",
"queue": "notifications",
"payload": {
"title": "Hello",
"body": "World"
}
}
Server → Client:
{
"id": "msg_001",
"type": "publishAck",
"headers": {
"messageId": "msg_001",
"queueName": "notifications"
}
}
Message Delivery
Server → Client:
{
"id": "msg_001",
"type": "deliver",
"queue": "notifications",
"payload": {
"title": "Hello",
"body": "World"
}
}
Client → Server:
{
"id": "ack_001",
"type": "ack",
"headers": {
"messageId": "msg_001"
}
}
Keep-alive
Client → Server:
{
"id": "ping_001",
"type": "ping"
}
Server → Client:
{
"id": "ping_001",
"type": "pong"
}
Protocol Versions
Current version: 1.1
Version |
Changes |
|---|---|
1.0 |
Base version |
1.1 |
Frame header extended with compression flags byte |
Next Steps
Architecture — system architecture
Features — VibeMQ capabilities
Monitoring — monitoring