skynet源码分析之sproto使用方法

A端主动给B端发送请求:调用request_encode对lua表进行编码,再用sproto.pack打包。

B端收到A端的请求:用sproto.unpack解包,再调用request_decode解码成lua表。

B端给A端发送返回包:用response_encode对lua表进行编码,然后用sproto.pack打包。

A端收到B端的返回包:用sproto.unpack解包,再调用request_decode解码成lua表。

不管是是request_encode还是response_encode,最终都会调用c层的encode接口,request_decode和response_decode都会调用c层decode接口。encode负责将lua数据表编码成二进制数据块,而decode负责解码,二者是互补操作。同样,pack和unpack也是互补操作。

-- lualib/sproto.lua
function sproto:request_encode(protoname, tbl)
    ...
    return core.encode(request,tbl) , p.tag
end

function sproto:response_encode(protoname, tbl)
    ...
    return core.encode(response,tbl)
end



function sproto:request_decode(protoname, ...)
    ...
    return core.decode(request,...) , p.name
end

function sproto:response_decode(protoname, ...)
    ...
    return core.decode(response,...)
end


sproto.pack = core.pack
sproto.unpack = core.unpack

1. encode编码

先放一个例子(在github上有),分析源码时会用到:

person { name = "Alice" ,  age = 13, marital = false } 

03 00 (fn = 3)
00 00 (id = 0, value in data part)
1C 00 (id = 1, value = 13)
02 00 (id = 2, value = false)
05 00 00 00 (sizeof "Alice")
41 6C 69 63 65 ("Alice")

encode的目的是按指定协议类型将lua表里的数据转化成c中的类型,然后按特定格式编码成一串二进制数据块。

最终调用sproto_encode api编码,有5个参数:st,sproto指定类型的c结构;buffer、size,存放编码结果的缓冲区和大小,如果缓冲区不够,会扩充缓冲区,重新编码;cb,对应lsproto.c中encode api,是一个c接口,负责获取lua表中指定key的值,或数组中指定索引位置的值;ud,额外信息,包含lua与c之间交互用的虚拟栈、sproto中对应类型的c结构等。

第3-6行,编码结果分两部分:头部header和数据data,header长度是固定的,等于2字节field总数+field的数目*2字节每个field长度。如下图:header指针指向缓冲区首地址,data指向header+header_sz位置,接下

 来编码每个field信息时,data指针会往后移动,而header指针保持不动。

第63-65行,将field的总数按大端格式打包长2字节大小(示例中的03 00),data指向header+header_sz处,最后用memmove将头部和数据块连在一起。

 接下来就是编码每一个field数据,根据field类型做不同的处理:

第11-13行,如果是array,调用encode_array编码,稍后介绍。

第33-37行,如果是string或自定义类型,调用encode_object编码,稍后介绍。

第16-32行,如果是integer或boolean类型,调用cb(lsproto.c中的encode)获取lua表中对应field名字的数值,保存到args.value(即u中)。第21行,变量value等于(原来的值+1)*2,因为编码后的0有特殊作用,为了区分原来值是0的情况。

第58-59行,最后将value按大端格式编码2字节,存到header指定的位置。比如示例中的1C 00,(13+1)*2=28=1C, 02 00,(0+1)*2=2=02,注:lua中的false会编码成0,true编码成1。如果是array、string或自定义类型,value是0,编码后是00 00,代表数值在data部分。 

第47-56行,如果某些tag没有设置值,需要把tag信息编码到header里。

// lualib/sproto/sproto.c
int sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_callback cb, void *ud) {
    uint8_t * header = buffer;
    uint8_t * data;
    int header_sz = SIZEOF_HEADER + st->maxn * SIZEOF_FIELD;
    data = header + header_sz;
    ...
    for (i=0;i<st->n;i++) {
        struct field *f = &st->f[i];
        int type = f->type;
        if
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值