diff options
-rw-r--r-- | PROTOCOL.md | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/PROTOCOL.md b/PROTOCOL.md new file mode 100644 index 0000000..9690fa5 --- /dev/null +++ b/PROTOCOL.md @@ -0,0 +1,168 @@ +# 协议定义 + +如无特殊说明: +- 本协议中所有字符串均采用**ASCII编码**表示为二进制值, + 如`"ABC"`表示字节序列`[65, 66, 67]`, + 而`"ABC\0"`表示`[65, 66, 67, 0]` +- 本协议中所有整数均采用**网络字节序的2的补码表示** + +## (I) 握手 + +### 1. 请求 +客户端向服务器发起TCP连接。在TCP连接建立后,客户端应首先发送**消息1**。 + +#### 消息1 +``` ++--------+------------------+------------------+ +| "PSMB" | version (uint32) | options (uint32) | ++--------+------------------+------------------+ +``` + +载荷说明: +- `"PSMB"`:协议头 +- `version`:版本号,服务器据此判断服务器和客户端双方的协议是否兼容 +- `options`:初始参数。目前,所有位均保留供将来使用,应设置为全零 + +### 2. 响应 + +1. 服务端读取4个字节,并判断是否为`"PSMB"`。如果不是,立刻断开连接。 +2. 服务端读出一个4字节无符号数,记为`ver`,判断`ver`是否为其兼容的版本号。如果不是,返回**消息2**,并立刻断开连接。 +3. 服务端读出32位长的比特数组,记为`options`,判断`options`的比特是否全部为零。如果不是,立刻断开连接。如果是,返回**消息3**。 + +#### 消息2 +``` ++--------------------------+ +| "UNSUPPORTED PROTOCOL\0" | ++--------------------------+ +``` + +载荷说明: +- `"UNSUPPORTED PROTOCOL\0"`:表示该协议版本不受服务端支持 + +#### 消息3 +``` ++--------+------------------+ +| "OK\0" | options (uint32) | ++--------+------------------+ +``` + +载荷说明: +- `"OK\0"`:表示服务端接受了客户端的传入连接,连接成功建立 +- `options`:服务端向客户端发送的选项。在当前版本,该字段应为全零 + +### 3. 客户端处理 + +- 客户端读入一个以`\0`结尾的字符串,如果是`"UNSUPPORTED PROTOCOL\0"`,断开连接; + 如果是`"OK\0"`,且继续读取32个比特全为0,则进入**状态(II)**;如果不是,断开连接 + + +## (II) 模式选择 + +### 1. 模式选择 +客户端选择本连接的类型,如果是`PUBLISH`,则发送**消息4**;如果是`SUBSCRIBE`,则发送**消息5**。 + +#### 消息4 +``` ++-------+--------------------------------------+ +| "PUB" | topic_id (str, terminated with '\0') | ++-------+--------------------------------------+ +``` + +载荷说明: +- `"PUB"`:表示该连接为`PUBLISH`类型。 + 客户端发送要发布的消息,服务端接收消息, + 并转发给订阅该话题的其他客户端 +- `topic_id`:该连接发布的消息的话题标识符,是一个字符串 + + +#### 消息5 +``` ++-------+------------------+----------------------------------------+-----+ +| "SUB" | options (uint32) | id_pattern (str, terminated with '\0') | ... | ++-------+------------------+----------------------------------------+-----+ +``` + +载荷说明: +- `"SUB"`:表示该连接为`SUBSCRIBE`类型。 + 客户端提供一个匹配模式串,服务端将来自所有标识符匹配该模式串的话题的消息转发给客户端。 +- `id_pattern`:模式串,一个**PCRE正则表达式**字符串。 +- `...`:可选载荷。按照从最低有效位到最高有效位的顺序遍历`options`中的每一位,如果该位为1,则读入一个选项。 + + 第0位:`ALLOW_HISTORY`。如果该为为1,则服务器将向客户端发送它没有接收过的所有消息,即有记忆功能。 + 选项: + ``` + +------------------------+ + | subscriber_id (uint64) | + +------------------------+ + ``` + +### 2. 响应 +服务端接收客户端的命令后,判断命令是否合法:读取3个字节,如果既不是`"PUB"`也不是`"SUB"`,返回**消息6**并断开连接。 +否则,如果接受该命令,返回**消息7**并进入**状态(III)**;如果拒绝该命令,返回**消息8**并保持在该状态。 + +#### 消息6 +``` ++-----------------+ +| "BAD COMMAND\0" | ++-----------------+ +``` + +#### 消息7 +``` ++--------+ +| "OK\0" | ++--------+ +``` + +#### 消息8 +``` ++------------+--------------------------------------------------------------------------------------------+ +| "FAILED\0" | error_message (str, terminated with '\0', read up to 128 Bytes including terminating '\0') | ++------------+--------------------------------------------------------------------------------------------+ +``` + + +## (III) 消息交换 +如果是`PUBLISH`模式,客户端向服务器发送消息,记主动方为客户端;如果是`SUBSCRIBE`模式,服务器向客户端发送消息,记主动方为服务端。 +无论是在哪种模式,主动方发送的消息都应为**消息9**或**消息10**的一种。 + +#### 消息9 +``` ++-------+-------------------------+----------------------------------+ +| "MSG" | message_length (uint64) | message (`message_length` bytes) | ++-------+-------------------------+----------------------------------+ +``` + +载荷说明: +- `"MSG"`:表示该消息是一个携带一个上层消息的报文 +- `message_length`:上层消息长度 +- `message`:上层消息,长度为`message_length`字节 + +#### 消息10 +``` ++-------+ +| "NOP" | ++-------+ +``` + +载荷说明: +- `"NOP"`:表示该消息是一个空指令,什么都不做(当经过*NAT设备*或*防火墙*时,可定时发送此消息以保持TCP连接)。接收方总是返回一个**消息12** + +#### 消息11 +``` ++-------+ +| "BYE" | ++-------+ +``` + +载荷说明: +- `"BYE"`:表示主动方将要终止连接。接收到此消息后,被动方(主动方的对方)也要终止连接 + +#### 消息12 +``` ++-------+ +| "NIL" | ++-------+ +``` + +载荷说明: +- `"NIL":表示一个空消息。接收方应总是丢弃该消息
\ No newline at end of file |