rpc框架yar之源码解析- 打包的实现
rpc框架yar的打包逻辑主要集中在:
yar_packager.h、yar_packager.c、和packagers/json.c、packagers/msgpack.c、 packagers/php.c三个文件。
我从一个网站上找了下面协议,我们一会儿会用到body_len的部分,打包主要针对h色部分。
yar_packager.h首先定义一个结构体,包括打包的名称,打包函数,解包函数的定义。
typedef struct _yar_packager { const char *name; int (*pack) (const struct _yar_packager *self, zval *pzval, smart_str *buf, char **msg); zval * (*unpack) (const struct _yar_packager *self, char *content, size_t len, char **msg, zval *rret);} yar_packager_t;
下面两行是定义两个函数,把各个yar_packager_t注册到一个list里面,然后通过传入的name返回相应的实例.
PHP_YAR_API int php_yar_packager_register(const yar_packager_t *packager);PHP_YAR_API const yar_packager_t * php_yar_packager_get(char *name, int nlen);
yar_packager.c
首先定义一个结构体,其中packagers是指向打包块的数组。
struct _yar_packagers_list {unsigned int size;unsigned int num;const yar_packager_t **packagers;} yar_packagers_list;
php_yar_packager_get函数的具体实现如下,通过name获得具体打包方式:
PHP_YAR_API const yar_packager_t * php_yar_packager_get(char *name, int nlen) /* {{{ */ { int i = 0; for (;i<yar_packagers_list.num;i++) { if (strncasecmp(yar_packagers_list.packagers[i]->name, name, nlen) == 0) { return yar_packagers_list.packagers[i]; } } return NULL;} /* }}} */
然后是php_yar_packager_register,即把打包方式注册到数组中。
// 首先 如果size=0,则分配5个空间,然后size=5。当注册数量从1到5,当num达到size个的时候。// 下次继续size+=5。以此类推。PHP_YAR_API int php_yar_packager_register(const yar_packager_t *packager) /* {{{ */ { if (!yar_packagers_list.size) { yar_packagers_list.size = 5; yar_packagers_list.packagers = (const yar_packager_t **)malloc(sizeof(yar_packager_t *) * yar_packagers_list.size); } else if (yar_packagers_list.num == yar_packagers_list.size) { yar_packagers_list.size += 5; yar_packagers_list.packagers = (const yar_packager_t **)realloc(yar_packagers_list.packagers, sizeof(yar_packager_t *) * yar_packagers_list.size); } yar_packagers_list.packagers[yar_packagers_list.num] = packager; return yar_packagers_list.num++;} /* }}} */
打包函数
zend_string *php_yar_packager_pack(char *packager_name, zval *pzval, char **msg) /* {{{ */ { char header[8]; smart_str buf = {0}; // 如果有name, 通过name获得具体的打包方式。否则则取全局的变量YAR_G(packager)。 const yar_packager_t *packager = packager_name ? php_yar_packager_get(packager_name, strlen(packager_name)) : YAR_G(packager); if (!packager) { php_error_docref(NULL, E_ERROR, "unsupported packager %s", packager_name); return 0; } memcpy(header, packager->name, 8); // 初始化变量buf,然后先追加header,其实就是打包的名称,占8个byte。 smart_str_alloc(&buf, YAR_PACKAGER_BUFFER_SIZE /* 1M */, 0); smart_str_appendl(&buf, header, 8); // 打包请求实体或者返回实体到buf中,并且返回。 packager->pack(packager, pzval, &buf, msg); if (buf.s) { smart_str_0(&buf); return buf.s; } // 如果buf为空,则释放内容。 smart_str_free(&buf); return NULL;} /* }}} */
解包程序
// content 为传入的字节流zval * php_yar_packager_unpack(char *content, size_t len, char **msg, zval *rret) /* {{{ */ { char *pack_info = content; /* 4 bytes, last byte is version */ const yar_packager_t *packager;// 取得content对应内容的前8位,然后在第8为设置成'\0', 代表结束。然后content取得从第9位开始的内容。// 记录body的长度则减去8位。content = content + 8; len -= 8; *(pack_info + 7) = '\0'; packager = php_yar_packager_get(pack_info, strlen(pack_info)); if (!packager) { spprintf(msg, 0, "unsupported packager '%s'", pack_info); return NULL; } // 然后调用具体的解包程序解包 return packager->unpack(packager, content, len, msg, rret);} /* }}} */
后面是注册yar_packager_msgpack, yar_packager_php, yar_packager_json三种方式
#ifdef ENABLE_MSGPACK php_yar_packager_register(&yar_packager_msgpack);#endif php_yar_packager_register(&yar_packager_php); php_yar_packager_register(&yar_packager_json);
下面是json, msgpack, php三种打包方式具体实现。
json.c主要以json格式对数据进行打包和解包。
// 调用php_json扩展进行处理int php_yar_packager_json_pack(const yar_packager_t *self, zval *pzval, smart_str *buf, char **msg) /* {{{ */ { #if ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 3)) php_json_encode(buf, pzval); #else php_json_encode(buf, pzval, 0); /* options */ #endif return 1;} /* }}} */zval * php_yar_packager_json_unpack(const yar_packager_t *self, char *content, size_t len, char **msg, zval *rret) /* {{{ */ { zval *return_value; php_json_decode(rret, content, len, 1, 512); return_value = rret; return return_value;} /* }}} */
msgpack.c
依赖于msgpack的扩展,关于msgpack的介绍,大家可以自己百度下。
// 这两行应该是 msgpack扩展包里的函数。extern void php_msgpack_serialize(smart_str *buf, zval *val);extern void php_msgpack_unserialize(zval *return_value, char *str, size_t str_len);int php_yar_packager_msgpack_pack(const yar_packager_t *self, zval *pzval, smart_str *buf, char **msg) /* {{{ */ { php_msgpack_serialize(buf, pzval); return 1;} /* }}} */zval * php_yar_packager_msgpack_unpack(const yar_packager_t *self, char *content, size_t len, char **msg, zval *rret) /* {{{ */ { zval *return_value; ZVAL_NULL(rret); php_msgpack_unserialize(rret, content, len); // 调用msgpack扩展函数进行 return_value = rret; return return_value;} /* }}} */
php.c
下面代码应该是利用php原生的serialize方法进行解析。
int php_yar_packager_php_pack(const yar_packager_t *self, zval *pzval, smart_str *buf, char **msg) /* {{{ */ { php_serialize_data_t var_hash; // php_serialize_data_t 是在php_var.h中定义HashTable类型的指针 PHP_VAR_SERIALIZE_INIT(var_hash); // 初始化这个HashTable php_var_serialize(buf, pzval, &var_hash); // PHP_VAR_SERIALIZE_DESTROY(var_hash); // 销毁掉这个HashTable return 1;} /* }}} */zval * php_yar_packager_php_unpack(const yar_packager_t *self, char *content, size_t len, char **msg, zval *rret) /* {{{ */ { zval *return_value; const unsigned char *p; php_unserialize_data_t var_hash; p = (const unsigned char*)content; PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(rret, &p, p + len, &var_hash)) { zval_ptr_dtor(rret); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); spprintf(msg, 0, "unpack error at offset %ld of %ld bytes", (long)((char*)p - content), len); return NULL; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return_value = rret; return return_value;} /* }}} */
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。