genProto ===== 用于根据自定义的协议文件生成 erl, c#, lua的序列化和反序列化代码 Build ----- rebar3 escriptize Use ----- rebar3 escriptize生成的genProto genPtoto.cmd 在_build/default/bin下面 将其复制到可以被搜索的执行路径或者工作目录 genProto ProtoInputDir HrlOutDir ErlOutDir # 简单描述 可用于erlang游戏或者erlang其他网络应用的协议解析编码解码的项目,具有较高的编码解码性能, 协议文件存放在proto目录 文件名为 Message protocol definition file的缩写 mpdf。 # 支持的数据类型 erl: int8 uint8 int16 uint16 int32 uint32 int64 uint64 integer(整数 64位) number(整数或者浮点数 64位) string float(32位浮点数) double(64位浮点数) bool record(struct) 以及上面类型的列表 lua(待修正): int8 uint8 int16 uint16 int32 uint32 int64 uint64 integer(整数 64位) number(整数或者浮点数 64位) string float(32位浮点数) double(64位浮点数) bool record 以及上面类型的列表 c#(待修正): int8 uint8 int16 uint16 int32 uint32 int64 uint64 integer(整数 64位) number(整数或者浮点数 64位) string float(32位浮点数) double(64位浮点数) bool record 以及上面类型的列表 # 各种数据类型的编码格式(字节序大端存储, string用utf8编码) int8: 直接存8bit的值 uint8: 直接存8bit的值 int16: 直接存16bit的值 uint16: 直接存16bit的值 int32: 直接存32bit的值 uint32: 直接存32bit的值 int64: 直接存64bit的值 uint64: 直接存64bit的值 integer: 如果值在int8范围区间: 8bit的Tag 值为8 + 8bit的值; 如果值在int16范围区间: 8bit的Tag 值为16 + 16bit的值; 如果值在int32范围区间: 8bit的Tag 值为32 + 32bit的值; 如果值在int64范围区间: 8bit的Tag 值为64 + 64bit的值; number: 如果值是整数则:编码规则同 integer类型; 如果是浮点数: 如果值在float32范围区间 8bit的Tag 值为33 + 32bit的值; 如果值在float64范围区间 8bit的Tag 值为65 + 64bit的值; string: 16bit的Tag 存放的字符串长度(长度不包含字符串结尾符) + 字符串的内容(内容不包含结字符串尾符号) float: 直接存放32bit的值 double: 直接存放64bit的值 bool: 占位8bit 如果为true 则存放的值为1 否则存放的值为0 record(struct): 如果是undefined 或者是空指针 则 8bit Tag 值为0, 否则 8bit的tag 值为1 + record的二进制数据 list_+上面的数据类型的时候: 16bit的tag 用于存放 数组的长度 + 按数组顺序序列化每个元素的值的二进制数据 ### maybe TODO 生成的protoMsg.erl encode 函数参数列表太长时 换行显示 encode返回的编码列表参数太多时 换行显示 decodeBin simple类型解码列表过长时 换行显示 decodeBin 返回元组元素太多时 换行显示 ### 关于消息接收转发解码和发送 erlang通常会将接收到的消息由网关进程转发给其他工作进程, 建议先匹配消息id, 然后转发二进制消息到工作进程,然后由工作进程解码再处理 同时广播消息可先编码成二进制之后再广播, 避免重复编码 ### erl部分简单性能测评 主要和gpb做简单对比测试 gpb测试相关文件在test/gpb目录下 测试协议: gpb: message test { required string aa = 1; } message phoneNumber { required test number = 1; required int32 type = 2; } message person { required string name = 1; required int32 integer = 2; optional string email = 3; repeated phoneNumber phone = 4; } message addressBook { repeated person person1 = 1; repeated person others = 2; } message tint32 { required int32 int1 = 1; required int32 int2 = 2; required int32 int3 = 3; required int32 int4 = 4; required int32 int5 = 5; required int32 int6 = 6; required int32 int7 = 7; required int32 int8 = 8; required int32 int9 = 9; required int32 int10 = 10; } genProto用的协议: test { string aa; } phoneNumber{ test number; int32 type; } person{ string name; int32 id; string email; list[phoneNumber] phone; } addressBook { list[person] person; list[person] other; } tint32{ int32 int1; int32 int2; int32 int3; int32 int4; int32 int5; int32 int6; int32 int7; int32 int8; int32 int9; int32 int10; } 测试运行三次 每次100万次循环 tint32 gpb-------->> tint32 encode: > timer:tc(mytest, encode_int32, [1000000]). {9625000,ok} > timer:tc(mytest, encode_int32, [1000000]). {9000000,ok} > timer:tc(mytest, encode_int32, [1000000]). {9969000,ok} tin32 decode: > timer:tc(mytest, decode_int32, [1000000]). {6217994,ok} > timer:tc(mytest, decode_int32, [1000000]). {6187993,ok} > timer:tc(mytest, decode_int32, [1000000]). {6265994,ok} size: > BTInt32 = mytest:decode_int32(1). <<8,1,16,255,255,255,255,255,255,255,255,255,1,24,128,1, 32,128,255,255,255,255,255,255,255,255,1,40,128,...>> 31> byte_size(BTInt32). 74 tint32 genProto ------->> tint32 encode: > timer:tc(test, encode_int32, [1000000]). {328999,ok} > timer:tc(test, encode_int32, [1000000]). {328000,ok} > timer:tc(test, encode_int32, [1000000]). {344000,ok} tint32 decode: > timer:tc(test, decode_int32, [1000000]). {328000,ok} > timer:tc(test, decode_int32, [1000000]). {328000,ok} > timer:tc(test, decode_int32, [1000000]). {329000,ok} size: > BTInt32 = test:decode_int32(1). <<0,11,0,0,0,1,255,255,255,255,0,0,0,128,255,255,255,128, 0,1,0,0,255,255,0,0,125,43,117,...>> > byte_size(BTInt32). 42 =============================================================================== =============================================================================== addressBook gpb-------->> addressBook encode: > timer:tc(mytest, encode_addressBook, [1000000]). {9108990,ok} > timer:tc(mytest, encode_addressBook, [1000000]). {8999991,ok} > timer:tc(mytest, encode_addressBook, [1000000]). {9031991,ok} addressBook decode: > timer:tc(mytest, decode_addressBook, [1000000]). {5702995,ok} > timer:tc(mytest, decode_addressBook, [1000000]). {5764994,ok} > timer:tc(mytest, decode_addressBook, [1000000]). {5718995,ok} size: > BAddr = mytest:decode_addressBook(1). <<10,43,10,5,65,108,105,99,101,16,144,78,34,15,10,11,10,9, 49,50,51,52,53,54,55,56,57,16,1,...>> > byte_size(BAddr). 75 addressBook genProto -------->> addressBook encode: > timer:tc(test, encode_addressBook, [1000000]). {4186995,ok} > timer:tc(test, encode_addressBook, [1000000]). {4202996,ok} > timer:tc(test, encode_addressBook, [1000000]). {4202996,ok} addressBook decode: > timer:tc(test, decode_addressBook, [1000000]). {2749997,ok} > timer:tc(test, decode_addressBook, [1000000]). {2812997,ok} > timer:tc(test, decode_addressBook, [1000000]). {2812997,ok} size: BAddr = test:decode_addressBook(1). <<0,4,0,2,0,5,65,108,105,99,101,0,0,39,16,0,0,0,2,1,0,9, 49,50,51,52,53,54,55,...>> 67> byte_size(BAddr). 83