雲風在skynet中繼承了sproto的傳輸協議,對比protobuf的好處是,能明文看到傳輸內容,而且skynet不需要protobuf這么功能,所以雲風也建議在lua層使用sproto來作為skynet的傳輸協議。
在examples文件夾中的agent.lua中有用到sproto的例子。下面講解一下sproto的使用過程和原理:
proto.lua的文件中包含一個實例協議:

1 local sprotoparser = require "sprotoparser" 2 3 local proto = {} 4 5 proto.c2s = sprotoparser.parse [[ 6 .package { 7 type 0 : integer 8 session 1 : integer 9 } 10 11 handshake 1 { 12 response { 13 msg 0 : string 14 } 15 } 16 17 get 2 { 18 request { 19 what 0 : string 20 } 21 response { 22 result 0 : string 23 } 24 } 25 26 set 3 { 27 request { 28 what 0 : string 29 value 1 : string 30 } 31 } 32 33 quit 4 {} 34 35 ]] 36 37 proto.s2c = sprotoparser.parse [[ 38 .package { 39 type 0 : integer 40 session 1 : integer 41 } 42 43 heartbeat 1 {} 44 ]] 45 46 return proto
proto.c2s是客戶端發送個服務端的協議,proto.s2c是服務端發送客戶端的協議。
sproto的協議變量類型有integer、string、boolean。sproto協議也可以實現結構體和數組、字典。
結構體的實現可以仿造.package,結構體開頭必須是以“.”開頭,"."后面的是結構體的名字,
字典和數組的實現是類似於c指針,例子如下:

1 local s2c = [[ 2 3 protoName 1 { 4 5 request { 6 7 arg1 0 :integer 8 9 arg2 1 :*value(key) 10 11 } 12 13 } 14 15 ]]
如果服務端要發送玩家擁有的角色信息的數組,key就是角色數組的索引數據類型,如果角色數組的索引是角色id的話,id類型是integer類型,那么key就是“integer”,
value是角色數組的頭元素。
sproto協議中也可以加注釋:在注釋內容前加上“#”符號。
sprotoparser.parse是通過sprotoparser.lua中的parse方法將協議解析成一個table,過程需要用到lpeg的庫來進行匹配。筆者到現在還沒弄懂這個parse過程,哈哈。。。
首先看看client.lua中的sproto的實現過程,
local sproto = require "sproto"
local host = sproto.new(proto.s2c):host "package"
local request = host:attach(sproto.new(proto.c2s))
sproto.new(proto.s2c):將proto.s2c闖入sproto.lua中,通過c的lsproto.c文件中的newproto方法將協議數據保存在sproto結構體中,sproto協議作為全局變量,一般情況下不需要gc,
最后返回一個sproto的table,具體實現還是要看看sproto.lua文件比較好理解。
host("package")是返回的sproto的table中查找“package”包頭,也就是.package結構體,和一些host的方法保存在一個新的table中,這個有點難理解,所以還是看看實現過程。
host:attach(sproto.new(proto.c2s))是通過上一步返回包頭協議,綁定在c2s的協議,返回一個負責打包協議的函數體,每次調用該函數時,傳入要打包的協議名,參數,和session就可以
得到一個協議結構體,例如:

1 send_request("set", { what = "hello", value = "world" })