skynet 学习笔记-sproto模块(2)
云风在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" })