欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Protocol Buffer技術(shù)深入理解(C++實(shí)例)

 更新時(shí)間:2013年01月04日 15:50:30   作者:  
C++實(shí)例Protocol Buffer技術(shù)詳解,感興趣的朋友可以了解下
這篇Blog仍然是以Google的官方文檔為主線(xiàn),代碼實(shí)例則完全取自于我們正在開(kāi)發(fā)的一個(gè)Demo項(xiàng)目,通過(guò)前一段時(shí)間的嘗試,感覺(jué)這種結(jié)合的方式比較有利于培訓(xùn)和內(nèi)部的技術(shù)交流。還是那句話(huà),沒(méi)有最好的,只有最適合的。我想寫(xiě)B(tài)log也是這一道理吧,不同的技術(shù)主題可能需要采用不同的風(fēng)格。好了,還是讓我們盡早切入主題吧。

一、生成目標(biāo)語(yǔ)言代碼
下面的命令幫助我們將MyMessage.proto文件中定義的一組Protocol Buffer格式的消息編譯成目標(biāo)語(yǔ)言(C++)的代碼。至于消息的內(nèi)容,我們會(huì)在后面以分段的形式逐一列出,同時(shí)也會(huì)在附件中給出所有源代碼。
復(fù)制代碼 代碼如下:

protoc -I=./message --cpp_out=./src ./MyMessage.proto

從上面的命令行參數(shù)中可以看出,待編譯的文件為MyMessage.proto,他存放在當(dāng)前目錄的message子目錄下。--cpp_out參數(shù)則指示編譯工具我們需要生成目標(biāo)語(yǔ)言是C++,輸出目錄是當(dāng)前目錄的src子目錄。在本例中,生成的目標(biāo)代碼文件名是MyMessage.pb.h和MyMessage.pb.cc。

二、簡(jiǎn)單message生成的C++代碼
這里先定義一個(gè)最簡(jiǎn)單的message,其中只是包含原始類(lèi)型的字段。
復(fù)制代碼 代碼如下:

option optimize_for = LITE_RUNTIME;
message LogonReqMessage {
required int64 acctID = 1;
required string passwd = 2;
}

由于我們?cè)贛yMessage文件中定義選項(xiàng)optimize_for的值為L(zhǎng)ITE_RUNTIME,因此由該.proto文件生成的所有C++類(lèi)的父類(lèi)均為::google::protobuf::MessageLite,而非::google::protobuf::Message。在上一篇博客中已經(jīng)給出了一些簡(jiǎn)要的說(shuō)明,MessageLite類(lèi)是Message的父類(lèi),在MessageLite中將缺少Protocol Buffer對(duì)反射的支持,而此類(lèi)功能均在Message類(lèi)中提供了具體的實(shí)現(xiàn)。對(duì)于我們的項(xiàng)目而言,整個(gè)系統(tǒng)相對(duì)比較封閉,不會(huì)和更多的外部程序進(jìn)行交互,與此同時(shí),我們的客戶(hù)端部分又是運(yùn)行在Android平臺(tái),有鑒于此,我們考慮使用LITE版本的Protocol Buffer。這樣不僅可以得到更高編碼效率,而且生成代碼編譯后所占用的資源也會(huì)更少,至于反射所能帶來(lái)的靈活性和極易擴(kuò)展性,對(duì)于該項(xiàng)目而言完全可以忽略。下面我們來(lái)看一下由message LogonReqMessage生成的C++類(lèi)的部分聲明,以及常用方法的說(shuō)明性注釋。
復(fù)制代碼 代碼如下:

class LogonReqMessage : public ::google::protobuf::MessageLite {
public:
LogonReqMessage();
virtual ~LogonReqMessage();
// implements Message ----------------------------------------------
//下面的成員函數(shù)均實(shí)現(xiàn)自MessageLite中的虛函數(shù)。
//創(chuàng)建一個(gè)新的LogonReqMessage對(duì)象,等同于clone。
LogonReqMessage* New() const;
//用另外一個(gè)LogonReqMessage對(duì)象初始化當(dāng)前對(duì)象,等同于賦值操作符重載(operator=)
void CopyFrom(const LogonReqMessage& from);
//清空當(dāng)前對(duì)象中的所有數(shù)據(jù),既將所有成員變量置為未初始化狀態(tài)。
void Clear();
//判斷當(dāng)前狀態(tài)是否已經(jīng)初始化。
bool IsInitialized() const;
//在給當(dāng)前對(duì)象的所有變量賦值之后,獲取該對(duì)象序列化后所需要的字節(jié)數(shù)。
int ByteSize() const;
//獲取當(dāng)前對(duì)象的類(lèi)型名稱(chēng)。
::std::string GetTypeName() const;
// required int64 acctID = 1;
//下面的成員函數(shù)都是因message中定義的acctID字段而生成。
//這個(gè)靜態(tài)成員表示AcctID的標(biāo)簽值。命名規(guī)則是k + FieldName(駝峰規(guī)則) + FieldNumber。
static const int kAcctIDFieldNumber = 1;
//如果acctID字段已經(jīng)被設(shè)置返回true,否則false。
inline bool has_acctid() const;
//執(zhí)行該函數(shù)后has_acctid函數(shù)將返回false,而下面的acctid函數(shù)則返回acctID的缺省值。
inline void clear_acctid();
//返回acctid字段的當(dāng)前值,如果沒(méi)有設(shè)置則返回int64類(lèi)型的缺省值。
inline ::google::protobuf::int64 acctid() const;
//為acctid字段設(shè)置新值,調(diào)用該函數(shù)后has_acctid函數(shù)將返回true。
inline void set_acctid(::google::protobuf::int64 value);
// required string passwd = 2;
//下面的成員函數(shù)都是因message中定義的passwd字段而生成。這里生成的函數(shù)和上面acctid
//生成的那組函數(shù)基本相似。因此這里只是列出差異部分。
static const int kPasswdFieldNumber = 2;
inline bool has_passwd() const;
inline void clear_passwd();
inline const ::std::string& passwd() const;
inline void set_passwd(const ::std::string& value);
//對(duì)于字符串類(lèi)型字段設(shè)置const char*類(lèi)型的變量值。
inline void set_passwd(const char* value);
inline void set_passwd(const char* value, size_t size);
//可以通過(guò)返回值直接給passwd對(duì)象賦值。在調(diào)用該函數(shù)之后has_passwd將返回true。
inline ::std::string* mutable_passwd();
//釋放當(dāng)前對(duì)象對(duì)passwd字段的所有權(quán),同時(shí)返回passwd字段對(duì)象指針。調(diào)用此函數(shù)之后,passwd字段對(duì)象
//的所有權(quán)將移交給調(diào)用者。此后再調(diào)用has_passwd函數(shù)時(shí)將返回false。
inline ::std::string* release_passwd();
private:
... ...
};

下面是讀寫(xiě)LogonReqMessage對(duì)象的C++測(cè)試代碼和說(shuō)明性注釋。
復(fù)制代碼 代碼如下:

void testSimpleMessage()
{
printf("==================This is simple message.================\n");
//序列化LogonReqMessage對(duì)象到指定的內(nèi)存區(qū)域。
LogonReqMessage logonReq;
logonReq.set_acctid(20);
logonReq.set_passwd("Hello World");
//提前獲取對(duì)象序列化所占用的空間并進(jìn)行一次性分配,從而避免多次分配
//而造成的性能開(kāi)銷(xiāo)。通過(guò)該種方式,還可以將序列化后的數(shù)據(jù)進(jìn)行加密。
//之后再進(jìn)行持久化,或是發(fā)送到遠(yuǎn)端。
int length = logonReq.ByteSize();
char* buf = new char[length];
logonReq.SerializeToArray(buf,length);
//從內(nèi)存中讀取并反序列化LogonReqMessage對(duì)象,同時(shí)將結(jié)果打印出來(lái)。
LogonReqMessage logonReq2;
logonReq2.ParseFromArray(buf,length);
printf("acctID = %I64d, password = %s\n",logonReq2.acctid(),logonReq2.passwd().c_str());
delete [] buf;
}

三、嵌套message生成的C++代碼
enum UserStatus {
OFFLINE = 0;
ONLINE = 1;
}
enum LoginResult {
LOGON_RESULT_SUCCESS = 0;
LOGON_RESULT_NOTEXIST = 1;
LOGON_RESULT_ERROR_PASSWD = 2;
LOGON_RESULT_ALREADY_LOGON = 3;
LOGON_RESULT_SERVER_ERROR = 4;
}
message UserInfo {
required int64 acctID = 1;
required string name = 2;
required UserStatus status = 3;
}
message LogonRespMessage {
required LoginResult logonResult = 1;
required UserInfo userInfo = 2; //這里嵌套了UserInfo消息。
}
對(duì)于上述消息生成的C++代碼,UserInfo因?yàn)橹皇前嗽碱?lèi)型字段,因此和上例中的LogonReqMessage沒(méi)有太多的差別,這里也就不在重復(fù)列出了。由于LogonRespMessage消息中嵌套了UserInfo類(lèi)型的字段,在這里我們將僅僅給出該消息生成的C++代碼和關(guān)鍵性注釋。
復(fù)制代碼 代碼如下:

class LogonRespMessage : public ::google::protobuf::MessageLite {
public:
LogonRespMessage();
virtual ~LogonRespMessage();
// implements Message ----------------------------------------------
... ... //這部分函數(shù)和之前的例子一樣。
// required .LoginResult logonResult = 1;
//下面的成員函數(shù)都是因message中定義的logonResult字段而生成。
//這一點(diǎn)和前面的例子基本相同,只是類(lèi)型換做了枚舉類(lèi)型LoginResult。
static const int kLogonResultFieldNumber = 1;
inline bool has_logonresult() const;
inline void clear_logonresult();
inline LoginResult logonresult() const;
inline void set_logonresult(LoginResult value);
// required .UserInfo userInfo = 2;
//下面的成員函數(shù)都是因message中定義的UserInfo字段而生成。
//這里只是列出和非消息類(lèi)型字段差異的部分。
static const int kUserInfoFieldNumber = 2;
inline bool has_userinfo() const;
inline void clear_userinfo();
inline const ::UserInfo& userinfo() const;
//可以看到該類(lèi)并沒(méi)有生成用于設(shè)置和修改userInfo字段set_userinfo函數(shù),而是將該工作
//交給了下面的mutable_userinfo函數(shù)。因此每當(dāng)調(diào)用函數(shù)之后,Protocol Buffer都會(huì)認(rèn)為
//該字段的值已經(jīng)被設(shè)置了,同時(shí)has_userinfo函數(shù)亦將返回true。在實(shí)際編碼中,我們可以
//通過(guò)該函數(shù)返回userInfo字段的內(nèi)部指針,并基于該指針完成userInfo成員變量的初始化工作。
inline ::UserInfo* mutable_userinfo();
inline ::UserInfo* release_userinfo();
private:
... ...
};

下面是讀寫(xiě)LogonRespMessage對(duì)象的C++測(cè)試代碼和說(shuō)明性注釋。
復(fù)制代碼 代碼如下:

void testNestedMessage()
{
printf("==================This is nested message.================\n");
LogonRespMessage logonResp;
logonResp.set_logonresult(LOGON_RESULT_SUCCESS);
//如上所述,通過(guò)mutable_userinfo函數(shù)返回userInfo字段的指針,之后再初始化該對(duì)象指針。
UserInfo* userInfo = logonResp.mutable_userinfo();
userInfo->set_acctid(200);
userInfo->set_name("Tester");
userInfo->set_status(OFFLINE);
int length = logonResp.ByteSize();
char* buf = new char[length];
logonResp.SerializeToArray(buf,length);
LogonRespMessage logonResp2;
logonResp2.ParseFromArray(buf,length);
printf("LogonResult = %d, UserInfo->acctID = %I64d, UserInfo->name = %s, UserInfo->status = %d\n"
,logonResp2.logonresult(),logonResp2.userinfo().acctid(),logonResp2.userinfo().name().c_str(),logonResp2.userinfo().status());
delete [] buf;
}

四、repeated嵌套message生成的C++代碼
message BuddyInfo {
required UserInfo userInfo = 1;
required int32 groupID = 2;
}
message RetrieveBuddiesResp {
required int32 buddiesCnt = 1;
repeated BuddyInfo buddiesInfo = 2;
}
對(duì)于上述消息生成的代碼,我們將只是針對(duì)RetrieveBuddiesResp消息所對(duì)應(yīng)的C++代碼進(jìn)行詳細(xì)說(shuō)明,其余部分和前面小節(jié)的例子基本相同,可直接參照。而對(duì)于RetrieveBuddiesResp類(lèi)中的代碼,我們也僅僅是對(duì)buddiesInfo字段生成的代碼進(jìn)行更為詳細(xì)的解釋。
復(fù)制代碼 代碼如下:

class RetrieveBuddiesResp : public ::google::protobuf::MessageLite {
public:
RetrieveBuddiesResp();
virtual ~RetrieveBuddiesResp();
... ... //其余代碼的功能性注釋均可參照前面的例子。
// repeated .BuddyInfo buddiesInfo = 2;
static const int kBuddiesInfoFieldNumber = 2;
//返回?cái)?shù)組中成員的數(shù)量。
inline int buddiesinfo_size() const;
//清空數(shù)組中的所有已初始化成員,調(diào)用該函數(shù)后,buddiesinfo_size函數(shù)將返回0。
inline void clear_buddiesinfo();
//返回?cái)?shù)組中指定下標(biāo)所包含元素的引用。
inline const ::BuddyInfo& buddiesinfo(int index) const;
//返回?cái)?shù)組中指定下標(biāo)所包含元素的指針,通過(guò)該方式可直接修改元素的值信息。
inline ::BuddyInfo* mutable_buddiesinfo(int index);
//像數(shù)組中添加一個(gè)新元素。返回值即為新增的元素,可直接對(duì)其進(jìn)行初始化。
inline ::BuddyInfo* add_buddiesinfo();
//獲取buddiesInfo字段所表示的容器,該函數(shù)返回的容器僅用于遍歷并讀取,不能直接修改。
inline const ::google::protobuf::RepeatedPtrField< ::BuddyInfo >&
buddiesinfo() const;
//獲取buddiesInfo字段所表示的容器指針,該函數(shù)返回的容器指針可用于遍歷和直接修改。
inline ::google::protobuf::RepeatedPtrField< ::BuddyInfo >*
mutable_buddiesinfo();
private:
... ...
};

下面是讀寫(xiě)RetrieveBuddiesResp對(duì)象的C++測(cè)試代碼和說(shuō)明性注釋。
復(fù)制代碼 代碼如下:

void testRepeatedMessage()
{
printf("==================This is repeated message.================\n");
RetrieveBuddiesResp retrieveResp;
retrieveResp.set_buddiescnt(2);
BuddyInfo* buddyInfo = retrieveResp.add_buddiesinfo();
buddyInfo->set_groupid(20);
UserInfo* userInfo = buddyInfo->mutable_userinfo();
userInfo->set_acctid(200);
userInfo->set_name("user1");
userInfo->set_status(OFFLINE);
buddyInfo = retrieveResp.add_buddiesinfo();
buddyInfo->set_groupid(21);
userInfo = buddyInfo->mutable_userinfo();
userInfo->set_acctid(201);
userInfo->set_name("user2");
userInfo->set_status(ONLINE);
int length = retrieveResp.ByteSize();
char* buf = new char[length];
retrieveResp.SerializeToArray(buf,length);
RetrieveBuddiesResp retrieveResp2;
retrieveResp2.ParseFromArray(buf,length);
printf("BuddiesCount = %d\n",retrieveResp2.buddiescnt());
printf("Repeated Size = %d\n",retrieveResp2.buddiesinfo_size());
//這里僅提供了通過(guò)容器迭代器的方式遍歷數(shù)組元素的測(cè)試代碼。
//事實(shí)上,通過(guò)buddiesinfo_size和buddiesinfo函數(shù)亦可循環(huán)遍歷。
RepeatedPtrField<BuddyInfo>* buddiesInfo = retrieveResp2.mutable_buddiesinfo();
RepeatedPtrField<BuddyInfo>::iterator it = buddiesInfo->begin();
for (; it != buddiesInfo->end(); ++it) {
printf("BuddyInfo->groupID = %d\n", it->groupid());
printf("UserInfo->acctID = %I64d, UserInfo->name = %s, UserInfo->status = %d\n"
, it->userinfo().acctid(), it->userinfo().name().c_str(),it->userinfo().status());
}
delete [] buf;
}

最后需要說(shuō)明的是,Protocol Buffer仍然提供了很多其它非常有用的功能,特別是針對(duì)序列化的目的地,比如文件流和網(wǎng)絡(luò)流等。與此同時(shí),也提供了完整的官方文檔和規(guī)范的命名規(guī)則,在很多情況下,可以直接通過(guò)函數(shù)的名字便可獲悉函數(shù)所完成的工作。

本打算將該Blog中使用的示例代碼以附件的方式上傳,但是沒(méi)有發(fā)現(xiàn)此功能,望諒解。

相關(guān)文章

  • C++使用宏函數(shù)實(shí)現(xiàn)單例模板詳解

    C++使用宏函數(shù)實(shí)現(xiàn)單例模板詳解

    在我們?nèi)粘i_(kāi)發(fā)中,無(wú)可避免需要使用單例模式進(jìn)行設(shè)計(jì)類(lèi)對(duì)象。這篇文章主要介紹了如何使用宏函數(shù)實(shí)現(xiàn)單例模板,感興趣的小伙伴可以了解一下
    2023-02-02
  • C++實(shí)現(xiàn)raw_input的方法

    C++實(shí)現(xiàn)raw_input的方法

    這篇文章主要介紹了C++實(shí)現(xiàn)raw_input的方法,通過(guò)C++來(lái)實(shí)現(xiàn)Python中發(fā)raw_input的方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2014-10-10
  • 從匯編看c++的默認(rèn)析構(gòu)函數(shù)的使用詳解

    從匯編看c++的默認(rèn)析構(gòu)函數(shù)的使用詳解

    本篇文章是對(duì)c++中默認(rèn)析構(gòu)函數(shù)的使用進(jìn)行了詳細(xì)的分析介紹。需要的朋友參考下
    2013-05-05
  • C語(yǔ)言編程中對(duì)目錄進(jìn)行基本的打開(kāi)關(guān)閉和讀取操作詳解

    C語(yǔ)言編程中對(duì)目錄進(jìn)行基本的打開(kāi)關(guān)閉和讀取操作詳解

    這篇文章主要介紹了C語(yǔ)言編程中對(duì)目錄進(jìn)行基本的打開(kāi)關(guān)閉和讀取操作,是C語(yǔ)言入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • C++ STL中的容器適配器實(shí)現(xiàn)

    C++ STL中的容器適配器實(shí)現(xiàn)

    這篇文章主要介紹了C++ STL中的容器適配器實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 解析C++中四種強(qiáng)制類(lèi)型轉(zhuǎn)換的區(qū)別詳解

    解析C++中四種強(qiáng)制類(lèi)型轉(zhuǎn)換的區(qū)別詳解

    本篇文章是對(duì)C++中四種強(qiáng)制類(lèi)型轉(zhuǎn)換的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • Qt 進(jìn)度條的實(shí)現(xiàn)示例

    Qt 進(jìn)度條的實(shí)現(xiàn)示例

    進(jìn)度條在很多時(shí)候都可以用到,有時(shí)我們需要在表格,樹(shù)狀欄中直觀顯示任務(wù)進(jìn)度或消耗百分比,本文就詳細(xì)的介紹一下Qt 進(jìn)度條的使用實(shí)例,感興趣的可以了解一下
    2021-06-06
  • C語(yǔ)言中#if的使用詳解

    C語(yǔ)言中#if的使用詳解

    #if和#endif是一組同時(shí)使用的,叫做條件編譯指令。#if與#define、#include等指令一樣是由預(yù)處理器這個(gè)強(qiáng)大的工具處理的,預(yù)處理器可以在編譯前處理c程序,這篇文章主要介紹了C語(yǔ)言中#if的使用,需要的朋友可以參考下
    2022-11-11
  • 基于C語(yǔ)言實(shí)現(xiàn)五子棋游戲

    基于C語(yǔ)言實(shí)現(xiàn)五子棋游戲

    這篇文章主要為大家詳細(xì)介紹了基于C語(yǔ)言實(shí)現(xiàn)五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • C語(yǔ)言實(shí)現(xiàn)飛機(jī)票務(wù)系統(tǒng)

    C語(yǔ)言實(shí)現(xiàn)飛機(jī)票務(wù)系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)飛機(jī)票務(wù)系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12

最新評(píng)論