WuKongIM 协议
控制报文结构
参数名 | 类型 | 说明 |
---|---|---|
Fixed header | 1 byte | 固定报头 |
Variable header | bytes | 可变报头 |
Payload | bytes | 消息体 |
固定报头
每个 WuKongIM 控制报文都包含一个固定报头
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
byte 1 | WuKongIM控制报文的类型 | 用于指定控制报文类型的标志位 | ||||||
byte 2... | 剩余长度 |
WuKongIM 控制报文的类型
名字 | 值 | 描述 |
---|---|---|
Reserved | 0 | 保留位 |
CONNECT | 1 | 客户端请求连接到服务器(c2s) |
CONNACK | 2 | 服务端收到连接请求后确认的报文(s2c) |
SEND | 3 | 发送消息(c2s) |
SENDACK | 4 | 收到消息确认的报文(s2c) |
RECV | 5 | 收取消息(s2c) |
RECVACK | 6 | 收取消息确认(c2s) |
PING | 7 | ping请求 |
PONG | 8 | 对ping请求的相应 |
DISCONNECT | 9 | 请求断开连接 |
用于指定控制报文类型的标志位
Send和Recv协议中的标志位
bit | 3 | 2 | 1 | 0 |
---|---|---|---|---|
byte | DUP | SyncOnce | RedDot | NoPersist |
Connack协议中的标志位
bit | 3 | 2 | 1 | 0 |
---|---|---|---|---|
byte | Reserved | Reserved | Reserved | HasServerVersion |
备注:
DUP: 是否是重复的消息(客户端重发消息的时候需要将DUP标记为1)
SyncOnce: 只同步一次 在多端设备的情况下 如果有一个设备拉取过此消息,其他设备将不会再拉取到此消息(比如加好友消息)
RedDot: 客户端收到消息是否显示红点
NoPersist: 是否不存储此消息
Reserved:保留位
HasServerVersion:是否有服务端版本号
剩余长度
在当前消息中剩余的 byte(字节)数,包含可变头部和负荷(内容)。
单个字节最大值:01111111,16 进制:0x7F,10 进制为 127。
WuKongIM 协议规定,第八位(最高位)若为 1,则表示还有后续字节存在。
WuKongIM 协议最多允许 4 个字节表示剩余长度。最大长度为:0xFF,0xFF,0xFF,0x7F,二进制表示为:11111111,11111111,11111111,01111111,十进制:268435455 byte=261120KB=256MB=0.25GB 四个字节之间值的范围:
Digits | From | To |
---|---|---|
1 | 0 (0x00) | 127 (0x7F) |
2 | 128 (0x80, 0x01) | 16 383 (0xFF, 0x7F) |
3 | 16 384 (0x80, 0x80, 0x01) | 2 097 151 (0xFF, 0xFF, 0x7F) |
4 | 2 097 152 (0x80, 0x80, 0x80, 0x01) | 268 435 455 (0xFF, 0xFF, 0xFF, 0x7F) |
其实换个方式理解:第 1 字节的基数是 1,而第 2 字节的基数:128,以此类推,第三字节的基数是:128128=2 的 14 次方,第四字节是:128128*128=2 的 21 次方;
例如,需要表达 321=2*128+65.(2 字节):10100001 0000 0011.
(和我们理解的低位运算放置顺序不一样,第一个字节是低位,后续字节是高位,但字节内部本身是低位右边,高位左边)。
字符串 UTF-8 编码
有关字符串,WuKongIM 采用的是修改版的 UTF-8 编码,一般形式为如下:
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
byte 1 | String Length MSB | |||||||
byte 2 | String Length MSB | |||||||
bytes 3... | Encoded Character Data |
可变报头
某些控制报文包含一个可变报头部分。它在固定报头和有效载荷之间。可变报头的内容根据报文类型的不同而不同。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里。
CONNECT 连接报文
参数名 | 类型 | 说明 |
---|---|---|
Packet Type | 0.5 byte | 报文类型(1) |
Flag | 0.5 byte | 标示位 |
Remaining Length | ... byte | 报文剩余长度 |
Protocol Version | int8 | 协议版本号 |
Device Flag | int8 | 设备标示(同标示同账号互踢) |
Device ID | string | 设备唯一ID |
UID | string | 用户ID |
Token | string | 用户的token |
Client Timestamp | int64 | 客户端当前时间戳(13位时间戳,到毫秒) |
Client Key | string | 客户端KEY (客户端KEY (base64编码的DH公钥)) |
CONNACK 连接确认
CONNACK 报文由服务端所发送,作为对来自客户端的 CONNECT 报文的响应,如果客户端在合理的时间内没有收到服务端的 CONNACK 报文,客户端应该关闭网络连接。合理的时间取决于应用的类型和通信基础设施。
参数名 | 类型 | 说明 |
---|---|---|
Packet Type | 0.5 byte | 报文类型(2) |
Flag | 0.5 byte | 标示位 |
Remaining Length | ... byte | 报文剩余长度 |
ServerVersion | uint8 | 服务器支持的最大版本 flag包含HasServerVersion的时候有效 |
Time Diff | int64 | 客户端时间与服务器的差值,单位毫秒。 |
Reason Code | uint8 | 连接原因码(见附件) |
Server Key | string | 服务端base64的DH公钥 |
Salt | string | 安全码 |
SEND 发送消息
参数名 | 类型 | 说明 |
---|---|---|
Packet Type | 0.5 byte | 报文类型(3) |
Flag | 0.5 byte | 标示位 |
Remaining Length | ... byte | 报文剩余长度 |
Setting | 1 byte | 消息设置 |
Client Seq | uint32 | 客户端消息序列号(由客户端生成,每个客户端唯一) |
Client Msg No | string | 客户端唯一标示,用于客户端消息去重 |
StreamNo | string | 流式消息编号(setting里需要开启Stream) |
Channel Id | string | 频道ID(如果是个人频道ChannelId为个人的UID) |
Channel Type | int8 | 频道类型(1.个人 2.群组) |
Expire | uint32 | 消息过期时间(单位秒) version>=3 |
Msg Key | string | 用于验证此消息是否合法(仿中间人篡改) |
Topic | string | 话题ID(只有setting开启了topic才有此字段) |
Payload | ... byte | 消息内容 |
SENDACK 发送消息确认
参数名 | 类型 | 说明 |
---|---|---|
Packet Type | 0.5 byte | 报文类型(4) |
Flag | 0.5 byte | 标示位 |
Remaining Length | ... byte | 报文剩余长度 |
Message ID | uint64 | 服务端的消息ID(全局唯一) |
Client Seq | uint32 | 客户端消息序列号 |
Message Seq | uint32 | 消息序号(有序递增,频道唯一) |
Reason Code | uint8 | 发送原因代码 1表示成功 |
SUB 订阅消息(研发中)
参数名 | 类型 | 说明 |
---|---|---|
Packet Type | 0.5 byte | 报文类型(5) |
Flag | 0.5 byte | 标示位 |
Remaining Length | ... byte | 报文剩余长度 |
Setting | 1 byte | 频道设置 |
SubNo | string | 订阅编号 |
Channel ID | string | 频道ID |
Channel Type | int8 | 频道类型 |
Action | int8 | 0.订阅 1.取消 |
Param | string | 订阅参数 |
SUBACK 订阅消息回执(研发中)
参数名 | 类型 | 说明 |
---|---|---|
Packet Type | 0.5 byte | 报文类型(5) |
Flag | 0.5 byte | 标示位 |
Remaining Length | ... byte | 报文剩余长度 |
SubNo | string | 订阅编号 |
Channel ID | string | 频道ID |
Channel Type | int8 | 频道类型 |
Action | int8 | 0.订阅 1.取消 |
Reason Code | uint8 | 订阅状态 1表示成功,其他代码见文档 |
RECV 收消息
参数名 | 类型 | 说明 |
---|---|---|
Packet Type | 0.5 byte | 报文类型(5) |
Flag | 0.5 byte | 标示位 |
Remaining Length | ... byte | 报文剩余长度 |
Setting | 1 byte | 消息设置(见下 版本4有效) |
Msg Key | string | 用于验证此消息是否合法(仿中间人篡改) |
From UID | string | 发送者UID |
Channel ID | string | 频道ID |
Channel Type | int8 | 频道类型 |
Expire | uint32 | 消息过期时间(单位秒) version>=3 |
Client Msg No | string | 客户端唯一标示,用于客户端消息去重 |
StreamNo | string | 流式消息编号,根据setting是否开启stream判断是否有此字段 |
StreamSeq | uint32 | 流序号,根据setting是否开启stream判断是否有此字段 |
StreamFlag | uint8 | 流标记(0.开始 1.进行中 2. 结束),根据setting是否开启stream判断是否有此字段 |
Message ID | uint64 | 服务端的消息ID(全局唯一) |
Message Seq | uint32 | 服务端的消息序列号(有序递增,频道唯一) |
Message Timestamp | int32 | 服务器消息时间戳(10位,到秒) |
Topic | string | 话题ID(只有setting开启了topic才有此字段) |
Payload | ... byte | 消息内容 |
RECVACK 收消息确认
参数名 | 类型 | 说明 |
---|---|---|
Packet Type | 0.5 byte | 报文类型(6) |
Flag | 0.5 byte | 标示位 |
Remaining Length | ... byte | 报文剩余长度 |
Message ID | uint64 | 服务端的消息ID(全局唯一) |
Message Seq | uint32 | 序列号 |
PING
参数名 | 类型 | 说明 |
---|---|---|
Packet Type | 0.5 byte | 报文类型(7) |
Flag | 0.5 byte | 标示位 |
PONG
参数名 | 类型 | 说明 |
---|---|---|
Packet Type | 0.5 byte | 报文类型(8) |
Flag | 0.5 byte | 标示位 |
DISCONNECT
参数名 | 类型 | 说明 |
---|---|---|
Packet Type | 0.5 byte | 报文类型(9) |
Flag | 0.5 byte | 标示位 |
Remaining Length | ... byte | 报文剩余长度 |
ReasonCode | uint8 | 原因代码 |
Reason | string | 原因 |
消息设置
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
byte | Receipt | Reserved | Signal | NoEncrypt | Topic | Stream | Reserved | Reserved |
消息设置目前大小为 1byte 8 个 bit
Receipt: 消息已读回执,此标记表示,此消息需要已读回执
NoEncrypt: 消息是否不开启加密
Signal: 加密
Topic:消息是否包含 topic(如果为 1 则发送包和接受包都将包含 topic 字段)
Stream: 流式消息
Reserved:保留位,暂未用到
Payload 推荐结构
普通消息
文本
{
"type": 1,
"content": "这是一条文本消息"
}
文本(带@)
{
"type": 1,
"content": "这是一条文本消息",
"mention":{
"all": 0, // 是否@所有人 0. @用户 1. @所有
"uids":["1223","2323"] // 如果all=1 此字段为空
}
}
文本(带回复)
{
"type": 1,
"content": "回复了某某" ,
"reply": {
"root_mid": "xxx", // 根消息的message_id
"message_id": "xxxx", // 被回复的消息ID
"message_seq": xxx, // 被回复的消息seq
"from_uid": "xxxx", // 被回复消息的发送者
"from_name": "xxx", // 被回复消息的发送者名称
"payload": {} // 被回复消息的payload
}
}
图片
{
"type": 2,
"url": "http://xxxxx.com/xxx", // 图片下载地址
"width": 200, // 图片宽度
"height": 320 // 图片高度
}
GIF
{
"type": 3,
"url": "http://xxxxx.com/xxx", // gif下载地址
"width": 72, // gif宽度
"height": 72 // gif高度
}
语音
{
"type": 4,
"url": "http://xxxxx.com/xxx", // 语音下载地址
"timeTrad": 10 // 语音秒长
}
文件
{
"type": 8,
"url": "http://xxxxx.com/xxx", // 文件下载地址
"name":"xxxx.docx", // 文件名称
"size": 238734 // 大小 单位byte
}
命令消息
{
"type": 99,
"cmd": "groupUpdate", // 命令指令标示
"param": {} // 命令对应的数据
}
系统消息
系统消息的 type 必须大于 1000
创建群聊 (NoPersist:0,RedDot:0,SyncOnce:1)
张三邀请李四、王五加入群聊
{
"type": 1001,
"creator": "xxx", // 创建者uid
"creator_name": "张三", // 创建者名称
"content": "{0}邀请{1}、{2}加入群聊",
"extra": [{"uid":"xxx","name":"张三"},{"uid":"xx01","name":"李四"},{"uid":"xx02","name":"王五"}]
}
添加群成员 (NoPersist:0,RedDot:0,SyncOnce:1)
张三邀请李四、王五加入群聊
{
"type": 1002,
"content": "{0}邀请{1}、{2}加入群聊",
"extra": [{"uid":"xxx","name":"张三"},{"uid":"xx01","name":"李四"},{"uid":"xx02","name":"王五"}]
}
移除群成员 (NoPersist:0,RedDot:0,SyncOnce:1)
张三将李四移除群聊
{
"type": 1003,
"content": "{0}将{1}移除群聊",
"extra": [{"uid":"xxx","name":"张三"},{"uid":"xx01","name":"李四"}]
}
群成员被踢 (NoPersist:0,RedDot:1,SyncOnce:0)
{
"type": 1010,
"content": "你被{0}移除群聊",
"extra": [{"uid":"xxx","name":"张三"}]
}
张三将李四移除群聊
{
"type": 1003,
"content": "{0}将{1}移除群聊",
"extra": [{"uid":"xxx","name":"张三"},{"uid":"xx01","name":"李四"}]
}
更新群名称 (NoPersist:0,RedDot:0,SyncOnce:1)
张三修改群名称为"测试群"
{
"type": 1005,
"content": "{0}修改群名为\"测试群\"",
"extra": [{"uid":"xxx","name":"张三"}]
}
更新群公告 (NoPersist:0,RedDot:0,SyncOnce:1)
张三修改群公告为"这是一个群公告"
{
"type": 1005,
"content": "{0}修改群公告为\"这是一个群公告\"",
"extra": [{"uid":"xxx","name":"张三"}]
}
撤回消息 (NoPersist:0,RedDot:0,SyncOnce:1)
张三撤回了一条消息
{
"type": 1006,
"message_id": "234343435", // 需要撤回的消息ID
"content": "{0}撤回了一条消息",
"extra": [{"uid":"xxx","name":"张三"}]
}
命令类消息
命令类消息 (SyncOnce:1)
{
"type": 99,
"cmd": "cmd", // 命令标示
"param": {} // 命令参数
}
群成员信息有更新(收到此消息客户端应该增量同步群成员信息)
{
"type": 99,
"cmd": "memberUpdate",
"param": {
"group_no": "xxxx"
}
}
红点消除(收到此命令客户端应将对应的会话信息的红点消除)
{
"type": 99,
"cmd": "unreadClear",
"param": {
"channel_id": "xxxx",
"channel_type": 2
}
}