久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Protocol Buffer使用簡介

 阿修羅之獅猿授 2016-07-11

我們項目中使用protocol buffer來進行服務器和客戶端的消息交互,服務器使用C++,所以本文主要描述protocol buffer C++方面的使用,其他語言方面的使用參見google的官方文檔.

1.概覽

1.1 什么是protocol buffer

protocol buffer是google的一個開源項目,它是用于結(jié)構(gòu)化數(shù)據(jù)串行化的靈活、高效、自動的方法,,例如XML,,不過它比xml更小,、更快,、也更簡單。你可以定義自己的數(shù)據(jù)結(jié)構(gòu),,然后使用代碼生成器生成的代碼來讀寫這個數(shù)據(jù)結(jié)構(gòu),。你甚至可以在無需重新部署程序的情況下更新數(shù)據(jù)結(jié)構(gòu)。

2.使用

2.1定義一個消息類型

message SearchRequest 
{
  required string query = 1;
  optional int32 page_number = 2;// Which page number do we want?
  optional int32 result_per_page = 3;// Number of results to return per page.
}

該消息定義了三個字段,兩個int32類型和一個string類型的字段,每個字段由字段限制,字段類型,字段名和Tag四部分組成.對于C++,每一個.proto文件經(jīng)過編譯之后都會對應的生成一個.h和一個.cc文件.

字段限制

字段限制共有3類:
required:必須賦值的字段
optional:可有可無的字段
repeated:可重復字段(變長字段),類似于數(shù)值
由于一些歷史原因,repeated字段并沒有想象中那么高效,新版本中允許使用特殊的選項來獲得更高效的編碼:

repeated int32 samples = 4 [packed=true];

Tags

消息中的每一個字段都有一個獨一無二的數(shù)值類型的Tag.1到15使用一個字節(jié)編碼,16到2047使用2個字節(jié)編碼,所以應該將Tags 1到15留給頻繁使用的字段.
可以指定的最小的Tag為$$1$$,最大為$$2^{29}-1$$或$$536,870,911$$.但是不能使用$$19000$$到$$19999$$之間的值,這些值是預留給protocol buffer的.

注釋

使用C/C++的//語法來添加字段注釋.

2.2 值類型

proto的值類型與具體語言中值類型的對應關系.

2.3 可選字段與缺省值

在消息解析時,如果發(fā)現(xiàn)消息中沒有包含可選字段,此時會將消息解析對象中相對應的字段設置為默認值,可以通過下面的語法為optional字段設置默認值:

optional int32 result_per_page = 3 [default = 10];

如果沒有指定默認值,則會使用系統(tǒng)默認值,對于string默認值為空字符串,對于bool默認值為false,對于數(shù)值類型默認值為0,對于enum默認值為定義中的第一個元素.

2.4 枚舉

message SearchRequest 
{
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3 [default = 10];
  enum Corpus 
  {
    UNIVERSAL = 0;
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }
  optional Corpus corpus = 4 [default = UNIVERSAL];
}

由于枚舉值采用varint編碼,所以為了提高效率,不建議枚舉值取負數(shù).這些枚舉值可以在其他消息定義中重復使用.

2.5 使用其他消息類型

可以使用一個消息的定義作為另一個消息的字段類型.

message Result 
{
  required string url = 1;
  optional string title = 2;
  repeated string snippets = 3;
}

message SearchResponse 
{
  repeated Result result = 1;
}

可以使用import語法來包含另外一個.proto文件.

import "myproject/other_protos.proto";

2.6 嵌套類型

在protocol中可以定義如下的嵌套類型

message SearchResponse 
{
  message Result 
  {
    required string url = 1;
    optional string title = 2;
    repeated string snippets = 3;
  }
  repeated Result result = 1;
}

如果在另外一個消息中需要使用Result定義,則可以通過Parent.Type來使用.

message SomeOtherMessage 
{
  optional SearchResponse.Result result = 1;
}

protocol支持更深層次的嵌套和分組嵌套,但是為了結(jié)構(gòu)清晰起見,不建議使用過深層次的嵌套,建議通過 2.5 小節(jié)提到的方法來實現(xiàn).

2.7 更新一個數(shù)據(jù)類型

在更新一個數(shù)據(jù)類型時更多的是需要考慮與舊版本的兼容性問題:

  1. 不要改變?nèi)魏我汛嬖谧侄蔚腡ag值,如果改變Tag值可能會導致數(shù)值類型不匹配,具體原因參加protocol編碼
  2. 建議使用optionalrepeated字段限制,盡可能的減少required的使用.
  3. 不需要的字段可以刪除,刪除字段的Tag不應該在新的消息定義中使用.
  4. 不需要的字段可以轉(zhuǎn)換為擴展,反之亦然只要類型和數(shù)值依然保留
  5. int32, uint32, int64, uint64, 和bool是相互兼容的,這意味著可以將其中一種類型任意改編為另外一種類型而不會產(chǎn)生任何問題
  6. sint32sint64是相互兼容的
  7. stringbytes是相互兼容的
  8. fixed32 兼容 sfixed32, fixed64 兼容 sfixed64.
  9. optional 兼容repeated

2.8 擴展

extend特性來讓你聲明一些Tags值來供第三方擴展使用.

message Foo 
{
  // ...
  extensions 100 to 199;
}

假如你在你的proto文件中定義了上述消息,之后別人在他的.proto文件中import你的.proto文件,就可以使用你指定的Tag范圍的值.

extend Foo 
{
  optional int32 bar = 126;
}

在訪問extend中定義的字段和,使用的接口和一般定義的有點不一樣,例如set方法:

    Foo foo;
    foo.SetExtension(bar, 15);

類似的有HasExtension(), ClearExtension(), GetExtension(), MutableExtension(), and AddExtension()等接口.

2.9 選項

  • optimize_for (file option): 可以設置的值有SPEED, CODE_SIZE, 或 LITE_RUNTIME. 不同的選項會以下述方式影響C++, Java代碼的生成.T
    • SPEED (default): protocol buffer編譯器將會生成序列化,語法分析和其他高效操作消息類型的方式.這也是最高的優(yōu)化選項.確定是生成的代碼比較大.
    • CODE_SIZE: protocol buffer編譯器將會生成最小的類,確定是比SPEED運行要慢
    • LITE_RUNTIME: protocol buffer編譯器將會生成只依賴"lite" runtime library (libprotobuf-lite instead of libprotobuf)的類. lite運行時庫比整個庫更小但是刪除了例如descriptors 和 reflection等特性. 這個選項通常用于手機平臺的優(yōu)化.
option optimize_for = CODE_SIZE;

3.常用API介紹

對于如下消息定義:

// test.proto
message PBStudent 
{    
    optional uint32 StudentID   = 1;
    optional string Name        = 2;
    optional uint32 Score       = 3;
}    

message PBMathScore
{    
    optional uint32 ClassID     = 1;  
    repeated PBStudent ScoreInf   = 2;
}

protocol buffer編譯器會為每個消息生成一個類,每個類包含基本函數(shù),消息實現(xiàn),嵌套類型,訪問器等部分.

3.1 基本函數(shù)

public:
 PBStudent();
 virtual ~PBStudent();

 PBStudent(const PBStudent& from);

 inline PBStudent& operator=(const PBStudent& from) {
   CopyFrom(from);
   return *this;
 }

 inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
   return _unknown_fields_;
 }

 inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
   return &_unknown_fields_;
 }

 static const ::google::protobuf::Descriptor* descriptor();
 static const PBStudent& default_instance();

 void Swap(PBStudent* other);

3.2 消息實現(xiàn)

PBStudent* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
void CopyFrom(const PBStudent& from);
void MergeFrom(const PBStudent& from);
void Clear();
bool IsInitialized() const;                                                                          

int ByteSize() const;
bool MergePartialFromCodedStream(
    ::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
    ::google::protobuf::io::CodedOutputStream* output) const;
::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;

3.3 嵌套類型

3.4 訪問器

// optional uint32 StudentID = 1;
inline bool has_studentid() const;
inline void clear_studentid();
static const int kStudentIDFieldNumber = 1;
inline ::google::protobuf::uint32 studentid() const;
inline void set_studentid(::google::protobuf::uint32 value);

// optional string Name = 2;
inline bool has_name() const;                                
inline void clear_name();
static const int kNameFieldNumber = 2;
inline const ::std::string& name() const;
inline void set_name(const ::std::string& value);
inline void set_name(const char* value);
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
inline void set_allocated_name(::std::string* name);

// optional uint32 Score = 3;                            
inline bool has_score() const;
inline void clear_score();
static const int kScoreFieldNumber = 3;
inline ::google::protobuf::uint32 score() const;
inline void set_score(::google::protobuf::uint32 value);

protocol buffer編譯器會對每一個字段生成一些getset方法,這些方法的名稱采用標識符所有小寫加上相應的前綴或后綴組成.生成一個值為Tags的k標識符FieldNum常量,

3.5 其他函數(shù)

除了生成上述類型的方法外, 編譯器還會生成一些用于消息類型處理的私有方法. 每一個.proto文件在編譯的時候都會自動包含message.h文件,這個文件聲明了很多序列化和反序列化,調(diào)試, 復制合并等相關的方法.

3.6 使用例子

在我們平時的使用中,通常一個message對應一個類,在對應的類中定義一個set和create方法來生成和解析PB信息.針對上述消息定義如下類:

// test.h
class CStudent
{
public:
    unsigned    mStudentID;
    unsigned    mScore;
    string      mName;

    CStudent()
    {
        Init();
    }

    inline void Init()
    {
        mStudentID = 0;
        mScore = 0;
        mName = "";
    }
}

class CMathScore
{
private:
    unsigned    mClassID;
    CStudent    mScoreInf[100];
public:
    CMathSCore()
    {
        Init();
    }
    ~CMathScore() {};

    void Init();
    void SetFromPB(const PBMathScore* pPB);
    void CreatePB(PBMathScore* pPB);

    // Get & Set mClassID
    ...
    // Get & set mScoreInf
    ...
    // some other function
    ...
}

對應的cpp文件中實現(xiàn)對PB的操作

// test.cpp
void CMathScore::Init()
{
    mClassID = 0;
    memset(mScoreInf, 0, sizeof(mScoreInf));
}

void CMathScore::SetFromPB(const PBMathScore* pPB)
{
    if ( NULL == pPB ) return;

    mClassID = pPB->classid();
    for(unsigned i = 0; i < (unsigned)pPB->scoreinf_size() && i < 100; ++i)
    {
        PBStudent* pStu = pPB->mutable_scoreinf(i);
        mScoreInf[i].mStudentID = pStu->studentid();
        mScoreInf[i].mScore        = pStu->score();
        mScoreInf[i].mName        = pStu->name();
    }
}

void CMathScore::CreatePB(PBMathScore* pPB)
{
    if ( NULL == pPB ) return;

    pPB->set_classid(mClassID);
    for(unsigned i = 0; i < 100; ++i)
    {
        PBStudent* pStu = pPB->add_scoreinf();
        pStu->set_studentid(mScoreInf[i].mStudentID)
        pStu->set_score(mScoreInf[i].mScore);
        pStu->set_name(mScoreInf[i].mName);        
    }
}

PB文件的讀寫

// use.cpp
#include<test.h>

#defind        MAX_BUFFER        1024 * 1024
int write()
{
    CMathScore    mMath;
    PBMathScore mPBMath;
    // use set functions to init member variable

    fstream fstm("./math.dat", ios::out | ios::binary);
    if ( fstm.is_open() == false )
    {
        return -1;
    }    
    char* tpBuffer = (char*)malloc(MAX_BUFFER);
    if ( NULL == tpBuffer )
    {
        return -2;
    }

    mMath.CreatePB(&mPBMath);
    if ( mPBMath.SerializeToArray(tpBuffer, mPBMath.ByteSize()) == false )
    {
        return -3;
    }
    fstm.write(tpBuffer, mPBMath.ByteSize());
    free(tpBuffer);
    fstm.close();

    return 0;
}

int read()
{
    CMathScore    mMath;
    PBMathScore mPBMath;

    fstream fstm.open("./math.dat", ios::out | ios::binary);
    if ( fstm.is_open() == false )
    {
        return -1;
    }    
    char* tpBuffer = (char*)malloc(MAX_BUFFER);
    if ( NULL == tpBuffer )
    {
        return -2;
    }
    char*    tpIdx = tpBuffer;
    int     tLen;
    while ( !fstm.eof() && tLen < MAX_BUFFER )
    {
        fstm.read(tpIdx, 1);
        tpIdx += 1;
        tLen++;
    }
    if ( mPBMath.ParseFromArray(tpBuffer, tLen - 1) == false )
    {
        return -3;
    }
    fstm.close();
    free(tpBuffer);
    tpIdx = NULL;

    mMath.SetFromPB(&mPBMath);
    // do some thing

    return 0;
}

    本站是提供個人知識管理的網(wǎng)絡存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多