使用 acl 庫針對 C++ 對象進行序列化及反序列編程


   在開發網絡應用程序時,各個模塊之間的數據通信可謂是家常便飯,為了應對這些數據通信時數據交換的要求,程序員發明了各種數據格式:采用二進制數據結構(早期 C 程序員)、采用 XML、采用SOAP(坑人的設計)、采用 URL 編碼、采用JSON格式等。客戶端與服務端交互時采用這些數據格式進行數據交換時,必然要經歷數據編碼及數據解碼的繁瑣過程。早期的二進制數據結構格式對於 C 程序員而是比較簡單的,在解碼時直接進行結構硬對齊就OK了,但對於其它語言(如 JAVA,PHP)則就麻煩很多,JAVA 語言不僅需要采用字節流一個一個對齊,而且還得要考慮到 C 結構體的數據打包填充方式;SOAP 方式看似滿足了各類編程語言數據交換的目的,但數據臃腫是一個很大的問題,我們為了傳輸幾個字節的數據則需要不得不封裝大量的 XML 標記。為了使跨語言開發的程序員從麻煩的數據編解碼中解脫出來,后來出來很多序列化/反序列化的工具庫,比較著名的象 Facebook 的 thrift,Google 的 protobuf。這些工具庫功能非常強大,但有一個問題是,這些工具庫所要求的預先定義的 schema 的親民性不夠好,增加了額外的大量學習成本。

      最近由 niukey@qq.com 為 acl 庫新增了 C++ 對象序列化與反序列化庫,大大提高了程序員的編程效率及代碼准確率。acl 序列化庫實現了 C++ struct 對象與 JSON 對象之間互轉功能,使用方式非常簡單。

 

      一、acl 序列化庫的功能特點

      1、可以直接將 C++ struct 對象轉換為 Json 對象,同時還可以將 Json 對象反序列化為 C++ struct 對象;

      2、支持 C++ struct 對象中包含構造函數及析構函數;

      3、C++ struct 對象中的成員支持常見基本類型(short, int, long, long long, char*)、標准 C++ 類對象;

      4、C++ struct 對象中的成員支持指針類型;

      5、C++ struct 對象中的成員支持常見 C++ 容器類型:std::vector、std::list、std::map,且支持容器對象的內部嵌套;

      6、C++ struct 對象中的成員為基本數據類型(如:short, int, long, long long)和指針類型時,支持直接在 struct 中針對這些成員進行初始化(C++11);

      7、支持在 C++ struct 中添加注釋(// 或 /**/);

      8、支持 C++ struct 對象的多繼承;

      9、支持在 C++ struct 對象中的多級包含,建議使用包含方式代替繼承方式;

      10、支持 C++ struct 成員增加注釋項://Gson@optional 表示該成員變量為可選項,//Gson@required 表示該成員為必須項,默認為必須的。

 

      二、使用 acl 序列化庫的限制

      1、struct 中的成員類型不能為 char 類型,主要是因為 Json 對象中不存在 char 類型;

      2、struct 中的成員前不得有 const 常量限定詞,主要是在反序列化時需要對這些成員進行賦值;

      3、struct 中不支持 C++ 關鍵詞:public、private、protected;

      4、struct 中的成員變量名不得為:$json、$node、$obj,因為這些關鍵詞被 acl 序列化庫生成的代碼占用;

      5、存在包含關系的 struct 類型定義必須在同一個文件中;

      6、不支持純 C 語言的數組功能,比如,針對 int a[10],因無法確切知道數組 a 中真實存儲的數量而無法進行序列化和反序列化,因此推薦使用 std::vector<int> 代替它。

 

      三、使用 acl 序列化庫的過程

      1、首先編譯 acl 庫:在 acl 目錄前運行:make build_one,會生成 acl 的三個基礎庫(lib_acl/lib/lib_acl.a, lib_protocol/lib/lib_protocol.a, lib_acl_cpp/liblib_acl_cpp.a),同時還會在 acl 根目錄下生成這三個庫的合集(lib_acl.a 和 lib_acl.so);

      2、編譯 acl 序列化工具:進入 app/gson 目錄,運行 make,生成 gson 工具,該工具將被用於根據用戶自定義 struct 生成序列化 C++ 代碼;

      3、定義自己的 struct 結構體(可以定義多個)並保存在文件中(文件后綴名為 .stub);

      4、使用 gson 工具根據用戶的 .stub 文件生成序列化所需的 C++ 代碼:./gson -d path,其中 path 為保含 .stub 文件的目錄,將會生成三個文件 gson.cpp、 gson.h 和 由 .stub 轉換的 .h 頭文件;

      5、將 gson.h 和由 .stub 文件轉換的 .h 頭文件包含在自己的代碼中;

      6、針對用戶自定義的每一個 struct,在 gson.h 頭文件中均會提供 struct 對象的序列化和反序列化的方法,假設用戶自定義了一個結構體類型:struct user,則在由工具 gson 生成的 gson.h 文件中包含如下五個方法:

      1)、acl::string gson(const user &$obj);

               將用戶填充好的 user 對象 $obj 轉換為 Json 字符串;

      2)、acl::json_node& gson(acl::json &$json, const user &$obj);

               將用戶填充好的 user 對象 $obj 轉化為 acl::json 對象 $json 中的一個 acl::json_node 節點對象並將之返回,這樣用戶可以將這個返回的 acl::json_node& 對象引用添加於 $json 對象中;

      3)、acl::json_node& gson(acl::json &$json, const user *$obj);

               功能與 2)中的方法相同,只是 $obj 參數為對象指針;

      4)、std::pair<bool,std::string> gson(acl::json_node &$node, user &$obj);

               將一個 acl::json_node Json 節點對象轉化為用戶自定義的 struct user 對象,如果 $node 為該 Json 對象中的根節點,則該根節點可由 $json.get_root() 獲得,$obj 存儲轉換后的結果;

      5)、std::pair<bool,std::string> gson(acl::json_node &$node, user *$obj);

               功能與 5)中的方法相同,只是 $obj 參數為對象指針。

 

      四、舉例:

      假設自定義結構對象如下:

Cpp代碼   收藏代碼
  1. // struct.stub  
  2. #pragma once  
  3. #include <string>  
  4.   
  5. struct user  
  6. {  
  7.         std::string name;  
  8.         std::string domain;  
  9.         int age;  
  10.         bool male;  
  11. };  

      應用操作 user 對象的過程如下:

Cpp代碼   收藏代碼
  1. // main.cpp  
  2. #include "stdafx.h"  
  3. #include <list>  
  4. #include <vector>  
  5. #include <map>  
  6. #include <stdio.h>  
  7. #include <iostream>  
  8. #include <time.h>  
  9. #include "struct.h"  // 由 gson 工具根據 struct.stub 轉換而成  
  10. #include "gson.h"   // 由 gson 工具根據 struct.stub 生成  
  11.   
  12. // 序列化過程  
  13. static void serialize(void)  
  14. {  
  15.     user u;  
  16.   
  17.     u.name = "zsxxsz";  
  18.     u.domain = "263.net";  
  19.     u.age = 11;  
  20.     u.male = true;  
  21.   
  22.     acl::json json;  
  23.   
  24.     // 將 user 對象轉換為 json 對象  
  25.     acl::json_node& node = acl::gson(json, u);  
  26.   
  27.     printf("serialize:\r\n");  
  28.     printf("json: %s\r\n", node.to_string().c_str());  
  29.     printf("\r\n");  
  30. }  
  31.   
  32. // 反序列化過程  
  33. static void deserialize(void)  
  34. {  
  35.     const char *s = "{\"name\": \"zsxxsz\", \"domain\": \"263.net\", \"age\": 11, \"male\": true}";  
  36.     printf("deserialize:\r\n");  
  37.   
  38.     acl::json json;  
  39.     json.update(s);  
  40.     user u;  
  41.   
  42.     // 將 json 對象轉換為 user 對象  
  43.     std::pair<bool, std::string> ret = acl::gson(json.get_root(), u);  
  44.   
  45.     // 如果轉換失敗,則打印轉換失敗原因  
  46.     if (ret.first == false)  
  47.         printf("error: %s\r\n", ret.second.c_str());  
  48.     else  
  49.         printf("name: %s, domain: %s, age: %d, male: %s\r\n",  
  50.             u.name.c_str(), u.domain.c_str(), u.age,  
  51.             u.male ? "yes" : "no");  
  52. }  
  53.   
  54. int main(void)  
  55. {  
  56.     serialize();  
  57.     deserialize();  
  58.     return 0;  
  59. }  

 

      五、參考:

      acl github:https://github.com/acl-dev/acl

      acl osc:https://git.oschina.net/acl-dev/acl/tree/master

      更多 C++ 序列化的例子:https://github.com/zhengshuxin/acl/tree/master/app/gson/test

      acl 編譯與使用:http://zsxxsz.iteye.com/blog/1506554


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM