skynet提供一套与客户端通讯的协议sproto,设计简单,有利于lua使用,参考官方wiki https://github.com/cloudwu/skynet/wiki/Sproto。本篇介绍组装".sproto"文件以及sproto构建流程。之后,会另写一篇介绍sproto的使用方法。
1. 组装.sproto文件流程
以下面简单的test.sproto文件为例介绍.sproto文件组装流程:
-- test.sproto .Person { name 0 : string id 1 : integer email 2 : string .PhoneNumber { number 0 : string type 1 : integer } phone 3 : *PhoneNumber } .AddresBook { person 0 : *Person } proto1 1001 { request { p 0 : integer } response { ret 0 : *Person } }
通过sparser.parse api组装.sproto文件,参数text即test.sproto文件的内容:
1 -- lualib/sprotoparser.lua 2 function sparser.parse(text, name) 3 local r = parser(text, name or "=text") 4 dump(r) 5 local data = encodeall(r) 6 sparser.dump(data) 7 return data 8 end
第3-4行,通过lpeg库将.sproto文件分析转化成一个lua表,部分结果如下,包含protocol和type两大类。protocol里包含所有的协议,每个协议有request,response,tag三个key;type里包含所有的类型,每个类型有1个或多个域(field),每个field里包含name,tag,typename等信息。
1 "protocol" = { 2 "proto1" = { 3 "request" = "proto1.request" 4 "response" = "proto1.response" 5 "tag" = 1001 6 } 7 } 8 "type" = { 9 "AddresBook" = { 10 1 = { 11 "array" = true 12 "name" = "person" 13 "tag" = 0 14 "typename" = "Person" 15 } 16 } 17 "Person" = { 18 1 = { 19 "name" = "name" 20 "tag" = 0 21 "typename" = "string" 22 } 23 ...
第5-6行,把lua表按特定格式组装成二进制数据后,结果如下(每一行16个字节):
1 02 00 00 00 00 00 65 01 - 00 00 32 00 00 00 02 00 2 00 00 00 00 0A 00 00 00 - 41 64 64 72 65 73 42 6F 3 6F 6B 1A 00 00 00 16 00 - 00 00 05 00 00 00 01 00 4 04 00 02 00 04 00 06 00 - 00 00 70 65 72 73 6F 6E 5 6E 00 00 00 02 00 00 00 - 00 00 06 00 00 00 50 65 6 72 73 6F 6E 5A 00 00 00 - 12 00 00 00 04 00 00 00 7 06 00 01 00 02 00 04 00 - 00 00 6E 61 6D 65 10 00 8 00 00 04 00 00 00 02 00 - 01 00 04 00 02 00 00 00 9 69 64 13 00 00 00 04 00 - 00 00 06 00 01 00 06 00 10 05 00 00 00 65 6D 61 69 - 6C 15 00 00 00 05 00 00 11 00 01 00 06 00 08 00 04 - 00 05 00 00 00 70 68 6F 12 6E 65 4E 00 00 00 02 00 - 00 00 00 00 12 00 00 00 13 50 65 72 73 6F 6E 2E 50 - 68 6F 6E 65 4E 75 6D 62 14 65 72 2E 00 00 00 14 00 - 00 00 04 00 00 00 06 00 15 01 00 02 00 06 00 00 00 - 6E 75 6D 62 65 72 12 00 16 00 00 04 00 00 00 02 00 - 01 00 04 00 04 00 00 00 17 74 79 70 65 2F 00 00 00 - 02 00 00 00 00 00 0E 00 18 00 00 70 72 6F 74 6F 31 - 2E 72 65 71 75 65 73 74 19 13 00 00 00 0F 00 00 00 - 04 00 00 00 02 00 01 00 20 02 00 01 00 00 00 70 34 - 00 00 00 02 00 00 00 00 21 00 0F 00 00 00 70 72 6F - 74 6F 31 2E 72 65 73 70 22 6F 6E 73 65 17 00 00 00 - 13 00 00 00 05 00 00 00 23 01 00 04 00 02 00 04 00 - 03 00 00 00 72 65 74 18 24 00 00 00 14 00 00 00 04 - 00 00 00 D4 07 08 00 0A 25 00 06 00 00 00 70 72 6F - 74 6F 31
通过这个结果(下面称为result)反推sproto组装流程:
第2-4行,按“<s4”格式打包字符串,即字符串长度占4个字节,按小端格式打包在头部,再加上字符串内容。
第14-22行,result前6个字节分别是"2 ",接下来分别是type的组装结果(tt)和protocol的组装结果(tp)。result7-10个字节是65 01 00 00,为type组装后的长度357(6*2^4+5+1*2^16)。 result从368个字节开始是protocol的组装结果,368-371个字节是18 00 00 00,表示protocol的组装结果有24个字节(1*2^4+8),即最后24个字节。
1 -- lualib/sprotoparser.lua 2 function packbytes(str) 3 return string.pack("<s4",str) 4 end 5 6 local function encodeall(r) 7 return packgroup(r.type, r.protocol) 8 end 9 10 local function packgroup(t,p) 11 ... 12 tt = packbytes(table.concat(tt)) 13 tp = packbytes(table.concat(tp)) 14 result = { 15 "2 ", -- 2fields 16 "