summaryrefslogtreecommitdiff
path: root/PROTOCOL.md
blob: 9690fa5fb7d6f6922919c4a9f911483911eccac0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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":表示一个空消息。接收方应总是丢弃该消息