rpc框架yar的打包邏輯主要集中在:
yar_packager.h、yar_packager.c、和packagers/json.c、packagers/msgpack.c、 packagers/php.c三個文件。php
我從一個網站上找了下面協議,咱們一下子會用到body_len的部分,打包主要針對h色部分。json
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;
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);
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,即把打包方式註冊到數組中。app
// 首先 若是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; } /* }}} */
解包程序ide
// 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格式對數據進行打包和解包。3d
// 調用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的擴展,關於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原生的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; } /* }}} */