skynet sproto协议剖析(四)

这篇分析数据通过sproto协议的打包和解包.有了前面的铺垫,分析打包和解包较为得简单.

在实际传输数据的时候我们都是根据协议名传输数据, 即protocol数组中的某个元素.所以在打包时我们必须知道是在打包哪个协议,解包的时候就知道了对应的是哪条协议了, 这个信息要写入打包之后数据的头部.其实sproto协议中第一个名为package的sproto_type就是来描述这个信息的.

区分每条协议最好用id,而不是string名字,这样有利用协议更改.所以每个协议都是有一个tag字段来对应其名字.所以package的sproto_type字段类型为integer.

刚才说过打包一个协议首先打包头部,包含其协议的tag. 例如打包下面的协议:

sp.request("TestReq", "{"age":15,"sex":"abc"}", ...)

首先得找到"TestReq"协议的tag,打进包头里面.这个很容易,前面讲构造协议时,sproto结构体包含了协议所有信息.根据协议名TestReq遍历proto字段即可.包头根据sproto_type字段里的name和个数,遍历即可找到名"package"的sproto_type结构.

同理找到要打包的数据对应sproto_type类型结构也不难,他的名字为"TestReq.request".

重点就是如何把数据打包了.打包也就是要写入数据,依照前面讲的数据格式,除了小integer型,其他都比较复杂,但总体上是先确定数据区域的偏移,写入数据,然后写入数据大小.下面对应常用的数据类型分别来分析.

打包代码的原型是:

int sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_callback cb, void *ud);

其中st是sproto_type类型,buffer,size是要传出的缓存地址和大小. cb是打包每种数据时的回调函数,做成回调函数的目的是业务与逻辑分离,做到接口之外定制,也就是我们自己定义打包的方式. ud则是打包函数与回调函数交互的介质.

对于字符串类型和自定义类型,都是调用encode_object函数:

static int
encode_object(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int size) {
	int sz;
	if (size < SIZEOF_LENGTH)
		return -1;
	args->value = data + SIZEOF_LENGTH;
	args->length = size - SIZEOF_LENGTH;
	sz = cb(args);
	if (sz < 0) {
		if (sz == SPROTO_CB_NIL)
			return 0;
		return -1;	// sz == SPROTO_CB_ERROR
	}
	assert(sz <= size - SIZEOF_LENGTH);	// verify buffer overflow
	return fill_size(data, sz);
}

可以看出他首先是确定要写入数据的地址,写完数据之后填入数据长度.要传入的数据和大小由args给出.

对于array数据,则多次循环调用打包数据,然后写入总长度,对于自定义数据则递归调用,详细的就不多说了.

解码则是打包的逆向过程,看看代码就能清楚了.

这篇写的比较粗糙,很多细节没有讲出来.其实只要对sproto协议做到心中有数,相信会理解.

参考:

https://www.cnblogs.com/RainRill/p/9002848.html


发布了135 篇原创文章 · 获赞 96 · 访问量 19万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览