0 1 2 3 4 5 6 7 bit
|-|-|-|-|-|-|-|-|
|-type -|d|qos|r|
|- message id -|
|- msgl-|-bytes-|
|- of length -|
|- body bytes -|
type: 消息类型
d:dup
qos: QoS
r: Retain
message id: 消息ID
msgl: 消息长度的字节数,除当前字节以外往后还有多少字节表示消息体字节数;msgl后面四比特是bytes of length的最低位四比特,后续是bytes of length剩余比特位按小端序编码。如果消息体字节数<16,则msgl是0。
对于没有消息体的消息类型,也没有msgl和bytes of length
message id
0 1 2 3 4 5 6 7
|-|-|-|-|-|-|-|-|
|msgname|process|//低4位是进程编号的字节数,
|serial number -|//小端序编码进程号
|ThreadIdAsInt64|//高4位是线程号除当前字节以外后面剩余字节数,低4位是线程号小端序低4位
|ThreadIdAsInt64|//线程号小端序编码
|- Timestamp -|//DateTime(t)编码
https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901027
消息体长度和编解码格式采用codec.md。其它特性尽量采用MQTT,以消息体字节数尽量少为第一优先级。
| Name | Value | Direction of flow | Description |
|---|---|---|---|
| AUTH | 0 | Client to Server | Connection request |
| SLAVEOF | 1 | Slave to Master | |
| REGISTER | 2 | Client to Server | Register new topic |
| PUBLISH | 3 | Client to Server or Server to Client | Publish message |
| RESERVED | 4 | ||
| PUBREC | 5 | Client to Server or Server to Client | Publish received (QoS 2 delivery part 1) |
| PUBREL | 6 | Client to Server or Server to Client | Publish release (QoS 2 delivery part 2) |
| PUBCOMP | 7 | Client to Server or Server to Client | Publish complete (QoS 2 delivery part 3) |
| SUBSCRIBE | 8 | Client to Server | Subscribe request |
| UNSUBSCRIBE | 9 | Client to Server | Unsubscribe request |
| CONSUME | 10 | Client to Server | consume messages |
| CONSUMERESP | 11 | Server to Client | |
| PINGREQ | 12 | Client to Server | PING request |
| ELECT | 13 | EACH OTHER among Masters | |
| ACK | 14 | Client to Server or Server to Client | |
| UNREGISTER | 15 | Unregister a topic | Unregister a topic |
- AUTH: 可以带鉴权数据,也可以没有,
- 除AUTH外,其它类型的消息可以设置IP白名单、黑名单,也可以按照消息体的鉴权信息确认是否可以访问
- 每一条消息体都要有唯一的messageId
- messaageId是18字节整数,开头4BIT是消息类型,中间是进程编号,然后是线程号,后面是DateTime.now().toUnixTimeStamp()
- 进程编号是进程在注册中心注册的编号,进程启动时要向注册中心注册,注册中心返回进程编号
- REGISTER: 用来注册主题
0 1 2 3 4 5 6 7
|-|-|-|-|-|-|-|-|
|0 0 1 0 0 0 0 0|
|- topic -|//不能有路径参数,可变的部分都要作为消息体传输,主题以主题字符串形式传输
|- queue count -|//队列数,默认是1
- ACK:AUTH PUBLISH SUBSCRIBE COMSUME PING REGISTER ELECT SLAVEOF
- 要返回messageId
- 客户端CONSUME,服务器响应CONSUMERESP,客户端再ACK
- 格式:
0 1 2 3 4 5 6 7 |-|-|-|-|-|-|-|-| |1 1 1 0 0 0 0 0| |- Req MSG id -|//发起访问时的messageId |- ........... -|//AUTH 的ACK还需要返回响应消息体, //AUTH需要响应鉴权结果, //ELECT响应消息体, 如果当前节点不同意对端议题,需要按照ELECT格式发送响应消息体,并以自身数据向其它节点发送ELECT。 如果当前节点同意对端议题,响应消息体是一字节的0,并以接收到的数据向其它节点发送ELECT。
| MQTT Control Packet | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|---|---|---|---|---|
| PUBLISH | DUP | QoS1 | Qos0 | RETAIN |
| CONSUME | 0 | 0 | ONCE | NEEDACK |
| ELECT | 0 | 0 | APPROVE | VOTE |
| SLAVEOF | 0 | 0 | 0 | REG |
| 以上没有提到的后四比特都是0 |
- SUBSCRIBE: 消息体包含消息ID、主题、消息TAG、消息需要满足的条件;返回进程号+整数序列号表示的订阅ID,以BigInt格式返回
- 主题可以带通配符
- 格式:
0 1 2 3 4 5 6 7 |-|-|-|-|-|-|-|-| |1 0 0 0 0 0 0 0| |- message id -|// |- topic -|//主题字符串或主题字符串的murmur_hash,带通配符的情况必须是字符串 |- tags -|//按字符串数组格式化(l) |- condition -|//按字符串格式化(s),仓颉逻辑表达式,支持&& || !和圆括号 |-ConsumerGroup-|//消费者组,按字符串格式化(s) - CONSUME:如果事先没有订阅,却发起CONSUME访问,说明当前客户端只消费一次,且每次都要以订阅消息体格式发送,如果事先已订阅,可以只发送订阅ID作为消息体。
- 可以使用CONSUME定义RPC
- CONSUME响应需要包含响应消息ID和响应的数据,对于MQ响应消息ID就是发布消息时的messageId,对于其它中间件需要服务端生成新的消息ID。
- ONCE:如果ONCE为1,则CONSUME只消费一次,如果为0,则CONSUME会持续消费,直到CONSUME返回ACK
- 1: 每次都需要发送主题、消息TAG、消息需要满足的条件、消费者组,这些内容按照SUBSCRIBE消息格式发送;且主题可以能带通配符
- 0:需要先SUBSCRIBE,每次CONSUME都发送消息ID和订阅ID
- NEEDACK:服务器返回CONSUMERESP,客户端再ACK,如果客户端一直没有ACK,服务器会重新发送
- ELECT:
- VOTE: 0: 发起投票,1:响应投票,发起投票时APPROVE是0,响应投票时APPROVE的值决定响应还是赞成
- APPROVE: 0: 否决,1:赞成,
0 1 2 3 4 5 6 7
|-|-|-|-|-|-|-|-|
|1 1 0 1 0 0 0 0|
|- message id -|//发起投票的messageId,后面的数据也是发起投票的数据
|- ipv -|lenOfIP|//ip以整数格式化
|- bytes of ip -|
|TwoBytesForPort|
|-VersionOfData-|//以整数表示的数据版本
- SLAVEOF:
- REG: 0注册从节点,1:获取从节点
//注册从节点时,后面是主节点的ip和port,ACK只返回message id //获取从节点时,消息体只有message id,ACK返回messageId和从节点列表 0 1 2 3 4 5 6 7 |-|-|-|-|-|-|-|-| |0 0 0 1 0 0 0 0| |- message id -|//发起投票的messageId,后面的数据也是发起投票的数据 |- ipv -|lenOfIP|//ip以整数格式化 |- bytes of ip -| |TwoBytesForPort|
DUP
Position: byte 1, bit 3.
If the DUP flag is set to 0, it indicates that this is the first occasion that the Client or Server has attempted to send this PUBLISH packet. If the DUP flag is set to 1, it indicates that this might be re-delivery of an earlier attempt to send the packet.
The DUP flag MUST be set to 1 by the Client or Server when it attempts to re-deliver a PUBLISH packet [MQTT-3.3.1-1]. The DUP flag MUST be set to 0 for all QoS 0 messages [MQTT-3.3.1-2].
The value of the DUP flag from an incoming PUBLISH packet is not propagated when the PUBLISH packet is sent to subscribers by the Server. The DUP flag in the outgoing PUBLISH packet is set independently to the incoming PUBLISH packet, its value MUST be determined solely by whether the outgoing PUBLISH packet is a retransmission [MQTT-3.3.1-3].
Non-normative comment
The receiver of an MQTT Control Packet that contains the DUP flag set to 1 cannot assume that it has seen an earlier copy of this packet.
Non-normative comment
It is important to note that the DUP flag refers to the MQTT Control Packet itself and not to the Application Message that it contains. When using QoS 1, it is possible for a Client to receive a PUBLISH packet with DUP flag set to 0 that contains a repetition of an Application Message that it received earlier, but with a different Packet Identifier. Section 2.2.1 provides more information about Packet Identifiers.
QoS
Position: byte 1, bits 2-1.
This field indicates the level of assurance for delivery of an Application Message. The QoS levels are shown below.
Table 3‑2 - QoS definitions
| QoS value | Bit 2 | bit 1 | Description |
|---|---|---|---|
| 0 | 0 | 0 | At most once delivery |
| 1 | 0 | 1 | At least once delivery |
| 2 | 1 | 0 | Exactly once delivery |
| - | 1 | 1 | Reserved – must not be used |
If the Server included a Maximum QoS in its CONNACK response to a Client and it receives a PUBLISH packet with a QoS greater than this, then it uses DISCONNECT with Reason Code 0x9B (QoS not supported) as described in section 4.13 Handling errors.
A PUBLISH Packet MUST NOT have both QoS bits set to 1 [MQTT-3.3.1-4]. If a Server or Client receives a PUBLISH packet which has both QoS bits set to 1 it is a Malformed Packet. Use DISCONNECT with Reason Code 0x81 (Malformed Packet) as described in section 4.13.
RETAIN
Position: byte 1, bit 0.
If the RETAIN flag is set to 1 in a PUBLISH packet sent by a Client to a Server, the Server MUST replace any existing retained message for this topic and store the Application Message [MQTT-3.3.1-5], so that it can be delivered to future subscribers whose subscriptions match its Topic Name. If the Payload contains zero bytes it is processed normally by the Server but any retained message with the same topic name MUST be removed and any future subscribers for the topic will not receive a retained message [MQTT-3.3.1-6]. A retained message with a Payload containing zero bytes MUST NOT be stored as a retained message on the Server [MQTT-3.3.1-7].
If the RETAIN flag is 0 in a PUBLISH packet sent by a Client to a Server, the Server MUST NOT store the message as a retained message and MUST NOT remove or replace any existing retained message [MQTT-3.3.1-8].
If the Server included Retain Available in its CONNACK response to a Client with its value set to 0 and it receives a PUBLISH packet with the RETAIN flag is set to 1, then it uses the DISCONNECT Reason Code of 0x9A (Retain not supported) as described in section 4.13.
When a new Non‑shared Subscription is made, the last retained message, if any, on each matching topic name is sent to the Client as directed by the Retain Handling Subscription Option. These messages are sent with the RETAIN flag set to 1. Which retained messages are sent is controlled by the Retain Handling Subscription Option. At the time of the Subscription:
· If Retain Handling is set to 0 the Server MUST send the retained messages matching the Topic Filter of the subscription to the Client [MQTT-3.3.1-9].
· If Retain Handling is set to 1 then if the subscription did not already exist, the Server MUST send all retained message matching the Topic Filter of the subscription to the Client, and if the subscription did exist the Server MUST NOT send the retained messages. [MQTT-3.3.1-10].
· If Retain Handling is set to 2, the Server MUST NOT send the retained messages [MQTT-3.3.1-11].
Refer to section 3.8.3.1 for a definition of the Subscription Options.
If the Server receives a PUBLISH packet with the RETAIN flag set to 1, and QoS 0 it SHOULD store the new QoS 0 message as the new retained message for that topic, but MAY choose to discard it at any time. If this happens there will be no retained message for that topic.
If the current retained message for a Topic expires, it is discarded and there will be no retained message for that topic.
The setting of the RETAIN flag in an Application Message forwarded by the Server from an established connection is controlled by the Retain As Published subscription option. Refer to section 3.8.3.1 for a definition of the Subscription Options.
· If the value of Retain As Published subscription option is set to 0, the Server MUST set the RETAIN flag to 0 when forwarding an Application Message regardless of how the RETAIN flag was set in the received PUBLISH packet [MQTT-3.3.1-12].
· If the value of Retain As Published subscription option is set to 1, the Server MUST set the RETAIN flag equal to the RETAIN flag in the received PUBLISH packet [MQTT-3.3.1-13].
Non-normative comment
Retained messages are useful where publishers send state messages on an irregular basis. A new non-shared subscriber will receive the most recent state.