summaryrefslogtreecommitdiff
path: root/PROTOCOL.md
diff options
context:
space:
mode:
Diffstat (limited to 'PROTOCOL.md')
-rw-r--r--PROTOCOL.md168
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