序
Yar是鳥哥惠新宸寫的一款并行RPC框架稿蹲,是國內(nèi)PHP圈內(nèi)主流的RPC方案選擇暴区,也是筆者公司服務(wù)化體系中的基礎(chǔ)組件紧武。為了更深入的理解其實現(xiàn)原理和熟悉該工具晌畅,抽空刷了遍源碼。整體來說閱讀難度不高<del>静袖,比看公司的legency代碼舒服</del>觉鼻。
研究之初是想寫個yar的swoole協(xié)程客戶端收尾的,但是隨著swoole4.1直接推出了Stream Hook勾徽,現(xiàn)在只能寫一下源碼分析了滑凉。話說起來這也是第二次為鳥哥的項目寫源碼分析了。讀完這個系列你應(yīng)該也能對yar的底層能有一個非常清晰的理解了喘帚。
出于模塊化的職業(yè)病拆成8章博客:
- PHP-yar拓展源碼解讀-packager篇
- PHP-yar拓展源碼解讀-protocol篇
- PHP-yar拓展源碼解讀-request/response篇
- PHP-yar拓展源碼解讀-client篇
- PHP-yar拓展源碼解讀-server篇
- PHP-yar拓展源碼解讀-transport篇
- PHP-yar拓展源碼解讀-concurrent_client篇
前三個章節(jié)講Yar的協(xié)議和核心數(shù)據(jù)結(jié)構(gòu)畅姊。
第四五七章講Yar PHP客戶端和服務(wù)端的實現(xiàn)。
第六七章主要講Yar網(wǎng)絡(luò)傳輸?shù)膶崿F(xiàn)細節(jié)吹由。
各個章節(jié)有一定依賴若未,篇幅也按順序增長,建議按序閱讀倾鲫。
另外為控制篇幅粗合,本系列中引用源碼會有少量刪減,特別一些非重要的條件編譯編譯分支乌昔,要研究某個功能的特定細節(jié)隙疚,建議另外直接翻源碼。
打包器
//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
表示一個打包器
磕道。打包器負責(zé)將一個IMP數(shù)組
(Request章節(jié)中會提到)或的ISRPE數(shù)組
(Resonse章節(jié)中會提到)進行序列化生成請求和響應(yīng)報文中載荷數(shù)據(jù)供屉。
一個yar_packager_t
變量包含三個成員,name
表示打包器的名字溺蕉,目前支持的三種打包方式對的name
分別為MSGPACK
伶丐,JSON
,PHP
,
pack()
和unpack()
分別為相關(guān)打包器的序列化和反序列化句柄疯特。
這是一種典型的OO風(fēng)格的C寫法哗魂,用結(jié)構(gòu)體和函數(shù)指針模擬抽象和多態(tài)。
打包器的注冊和獲取
//yar_packager.c
struct _yar_packagers_list {
unsigned int size;
unsigned int num;
const yar_packager_t **packagers;
} yar_packagers_list;
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_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++;
} /* }}} */
yar_packagers_list
作為list儲存管理多個yar_packager_t
漓雅,注冊和獲取時均需要時遍歷該list獲取yar_packagers_list->packagers
录别。list實現(xiàn)簡單,而且成員反正就3個邻吞,所以O(shè)(n)也不會有任何問題庶灿,transport模塊也是同樣的使用list實現(xiàn)注冊和獲取。
//yar_packager.c
zend_string *php_yar_packager_pack(char *packager_name, zval *pzval, char **msg) /* {{{ */ {
char header[8];
smart_str buf = {0};
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);
smart_str_alloc(&buf, YAR_PACKAGER_BUFFER_SIZE /* 1M */, 0);
smart_str_appendl(&buf, header, 8);
packager->pack(packager, pzval, &buf, msg);
if (buf.s) {
smart_str_0(&buf);
return buf.s;
}
smart_str_free(&buf);
return NULL;
} /* }}} */
序列化字符串前8個字符固定用于表示packager的類型吃衅,\0
表示字符串末尾,中間的字符串由具體的packager對變量進行處理生成往踢。
打包器類型
如前問所述,packager目前的實現(xiàn)有3種:
- MSGPACK
- PHP
- JSON
php
// packager\php.c
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_VAR_SERIALIZE_INIT(var_hash);
php_var_serialize(buf, pzval, &var_hash);
PHP_VAR_SERIALIZE_DESTROY(var_hash);
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;
} /* }}} */
該方式實際上就是就是我們平常使用的serialize()
,unserialize
函數(shù)徘层。
json
//packager\json.c
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;
} /* }}} */
json方式使用json拓展的json_encode()
峻呕,json_decode()
對變量進行序列化操作
msgpack
//packager\msgpack.c
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);
return_value = rret;
return return_value;
} /* }}} */
而yar_packager_msgpack
使用msgpack拓展的php_msgpack_serialize()
和php_msgpack_unserialize()
函數(shù)對變量進行序列化。3種序列化方式中該種傳輸效率最高趣效,空間使用最小瘦癌, 使用該方式需要自行安裝msgpack-php
拓展并在編譯yar時候使用--enable-msgpack
參數(shù)。