servicecall_socket - catyguan/sad GitHub Wiki
地址的Type为socket
地址的API为具体的一个格式符号,格式如下
[SOCKET类型]:[主机地址]:[端口]:[服务名称]:[方法名称]
- SOCKET类型 —— tcp, tcp4, tcp6, udp, udp4, udp6, unix
- 主机地址 —— 形式可以为IP,域名或unix路径
- 端口 —— unix类型,可以不设置
- 在实际的使用过程中,可以采用占位符($SNAME$,
$MNAME$ )定义通用的服务接口API
例如: tcp:127.0.0.1:8080:test:hello
[行][行][行]...[结束行]
[1字节:行类型][3字节:数据大小,BigEndian][X字节:数据,X由'数据大小'决定]
例子:行类型为1,长度为1000
[1][0][3][232][0xAB]...x1000
行最大的数据大小为 256 * 256 * 256 = 16777216 / 1024 / 1024 = 16M
当数据体大于16M的时候,可拆分多行进行传输(具体可阅读后续的相关章节)
头行
体行
结束行
排列顺序:[头行] 0或多个, [体行] 0或多个, [结束行] 1个
头行必须在非头行之前,结束行必须是消息的最后一行,同一类别的行之间无顺序要求(业务有特别要求除外)
结束行 = 行类型为0,数据大小为0的行
[0][0][0][0]
Bool : 布尔值,1字节
0 false
非0 true
UInt32,UInt64 : 变长的无符号整型数据
编码:
i := 0
for v >= 0x80 {
buf[i] = byte(v) | 0x80
v >>= 7
i++
}
buf[i] = byte(v)
return i + 1
解码:
var x uint64
var s uint
for i, b := range buf {
if b < 0x80 {
if i > 9 || i == 9 && b > 1 {
return 0, -(i + 1) // overflow
}
return x | uint64(b)<<s, i + 1
}
x |= uint64(b&0x7f) << s
s += 7
}
return 0, 0
Int32,Int64 : 变长的有符号整型数据
编码:
uv := uint64(v) << 1
if v < 0 {
uv = ^uv // 取反 ~uv
}
return UIntXEncoder(uv)
解码:
func UIntXDecoder(buf) {
ux, n := UIntXDecoder(buf)
x := int64(ux >> 1)
if ux&1 != 0 {
x = ^x // 取反 ~x
}
return x, n
FixInt8, FixInt16, FixInt32, FixInt64 : 定长的数据
编码顺序 BigEndian
8为1个字节
16为2个字节
32为4个字节
64为8个字节
Float32 : 定长的4字节浮点数据
根据IEEE 754格式转换为uint32然后FixUInt32编码
Float64 : 定长的8字节浮点数据
根据IEEE 754格式转换为uint64然后FixUInt64编码
Bytes : 二进制数据,不定长
String : UTF8编码字符串,不定长
LenBytes : 具有长度的二进制数据
[字节长度:Int32][Bytes]
LenString : 具有长度的字符串
[字节长度:Int32][String]
Var : 类型长度都不定的数据
[数据类型:1个字节][数据体]
数据类型编号
0 - Null
1 - Bool
2 - Int32
3 - Int64
4 - Float32
5 - Float64
6 - LenString
8 - List<Var>
[List数量:Int32][Value:Var]...
9 - Map<String, Var>
[Map数量:Int32][[Key:LenString][Value:Var]]...
10 - Binary
LenBytes
MT_END : 0x00
结束行,必须设置
无数据,为 [0][0][0][0]
MT_MESSAGE_ID : 0x01
头行,必须设置
基于Socket连接的消息编号,同一通信通道该编号按照通信次数增加
数据体:[FixInt32]
MT_REQUEST : 0x02
头行,必须设置
该消息为请求
无数据体,为 [2][0][0][0]
MT_ADDRESS : 0x03
头行,必须设置
数据体:[服务名称:LenString][方法名称:LenString]
MT_DATA : 0x04
体行
请求数据。一行对应一个Request数据
数据体:[名称:LenString][数据:Var]
MT_CONTEXT : 0x05
体行
上下文数据。一行对应一个Context数据
数据体:[名称:LenString][数据:Var]
MT_END : 0x00
结束行,必须设置
无数据,为 [0][0][0][0]
MT_MESSAGE_ID : 0x01
头行,必须设置
应答的消息编号,基于Socket连接
数据体:[FixInt32]
MT_ANSWER : 0x06
头行,必须设置
应答的状态
数据体:[Status:Int32][Message:LenString]
MT_DATA : 0x04
体行
响应数据。一行对应一个Response数据
数据体:[名称:LenString][数据:Var]
MT_CONTEXT : 0x05
体行
应答上下文数据。一行对应一个Context数据
数据体:[名称:LenString][数据:Var]
和上述协议一致
当一个体行的数据体大于16M的时候,需要采用大数据跨行协议。
MT_MLINE : 0x07
体行
传输大数据的行。接受方把多条MLINE数据合并后再按一行的数据进行处理。MLINE数据的相关行需要顺序发送
数据体:[编号:Int32][当前序号:Int32][最大序号:Int32][数据:LenBytes]
- 编号用于区分不同的MLINE数据
- 当前序号从1开始
- 最大序号可以为0,表示未知
- 当前序号 = 最大序号 表示已全部发送(该MLINE数据的最后一行)
PING用于检测SOCKET的可用性。
消息包只有2行:MT_PING和MT_END。由客户端发起,服务端接收后发送PING应答
服务端SOCKET一般不做主动发送,所以可采用超时关闭的方法保证SOCKET的可用性
MT_PING : 0x09
头行
数据体:[是否应答:Bool]
ServerPush用于异步调用响应,会在一个调用中返回多个应答(客户端一个MessageId的消息包,有多个服务端对应MessageId的消息包)
具体协议说明:
- 客户端发送MessageId=M1的请求调用,并设置AsyncMode为callback
- 服务端响应MessageId=M1,Status=202的应答
- 服务端后续可继续主动发送MessageId=M1,Status=202的应答,期间需保持该连接一致
- 服务端发送MessageId=M1,Status!=202的应答,结束ServerPush通信过程