中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

rpc框架yar之源碼解析- 打包的實現

發布時間:2020-07-16 12:35:06 來源:網絡 閱讀:1007 作者:netbird_fly 欄目:開發技術

yar源碼解析之打包


rpc框架yar的打包邏輯主要集中在:
yar_packager.h、yar_packager.c、和packagers/json.c、packagers/msgpack.c、 packagers/php.c三個文件。

我從一個網站上找了下面協議,我們一會兒會用到body_len的部分,打包主要針對h色部分。

rpc框架yar之源碼解析- 打包的實現

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;
} /* }}} */
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

黔江区| 萨迦县| 昌黎县| 新兴县| 房产| 临潭县| 康马县| 郧西县| 黑山县| 新宁县| 仪征市| 咸阳市| 齐齐哈尔市| 北安市| 璧山县| 九江市| 崇左市| 莎车县| 马公市| 花莲县| 旅游| 湾仔区| 榆中县| 太湖县| 仙游县| 通州市| 杭锦后旗| 南平市| 泽州县| 社会| 玉田县| 鄯善县| 文登市| 大丰市| 青河县| 北海市| 根河市| 武宣县| 普洱| 石家庄市| 平利县|