• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            牽著老婆滿街逛

            嚴以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            Protobuf和FlatBuffers以及ByteBuffer的應用

            Protobuf版本號:3.1.0
            FlatBuffers版本號:1.4.0



            Protobuf

            首先來一發pb3的IDL代碼Helloworld.proto
            syntax = "proto2";

            package proto.helloworld;

            message HelloWorld
            {
                required int32 id = 1;        // id
                required string str = 2;    // str
                optional int32 opt = 3;        // optional field
            }

            使用命令行或者編寫一個bat批處理文件
            @set path=..\..\..\..\third_party\protobuf\bin\release;%path%
            @cls

            :: /////////////////////////////////////////////////////////////
            ::
            :: 編譯Protobuf協議
            ::
            :: /////////////////////////////////////////////////////////////
            protoc --version

            protoc --cpp_out=../ ./Helloworld.proto

            pause
            執行以上的批處理文件,將會在其目錄的上一層目錄下生成兩個源碼文件:Helloworld.pb.h和Helloworld.pb.cc.
            將生成的這倆文件拖進工程里面去,至于vc的StdAfx,預編譯頭的問題,很好解決.在cc文件上點右鍵->屬性->C/C++->預編譯頭->預編譯頭(不使用預編譯頭),這事兒就妥妥的解決了.

            以下列舉序列化到三種目標里去的實例
            1.std::string
            void testString()
            {
                //////////////////////////////////////////////////////////////////////////
                // 編碼
                //////////////////////////////////////////////////////////////////////////
                proto::helloworld::HelloWorld msg_encode;
                msg_encode.set_id(10086);
                msg_encode.set_str("hello world");
                msg_encode.set_opt(10000);

                std::string str_data;
                bool encode_ok = msg_encode.SerializeToString(&str_data);
                ASSERT(encode_ok);

                //////////////////////////////////////////////////////////////////////////
                // 解碼
                //////////////////////////////////////////////////////////////////////////
                proto::helloworld::HelloWorld msg_decode;
                bool decode_ok = msg_decode.ParseFromString(str_data);
                ASSERT(decode_ok);
                size_t n = str_data.length();

                ASSERT(msg_decode.id() == 10086);
                ASSERT(msg_decode.str().compare("hello world") == 0);
                ASSERT(msg_decode.opt() == 10000);
            }

            2.ByteArray(char [])
            void testByteArray()
            {
                //////////////////////////////////////////////////////////////////////////
                // 編碼
                //////////////////////////////////////////////////////////////////////////
                proto::helloworld::HelloWorld msg_encode;
                msg_encode.set_id(10086);
                msg_encode.set_str("hello world");
                msg_encode.set_opt(10000);

                char msg_buf[1024];
                ZeroMemory(msg_buf, sizeof(msg_buf));
                bool encode_ok = msg_encode.SerializeToArray(msg_buf, sizeof(msg_buf));
                ASSERT(encode_ok);
                int encode_size = msg_encode.ByteSize();

                //////////////////////////////////////////////////////////////////////////
                // 解碼
                //////////////////////////////////////////////////////////////////////////
                proto::helloworld::HelloWorld msg_decode;
                bool decode_ok = msg_decode.ParseFromArray(msg_buf, encode_size);
                ASSERT(decode_ok);

                ASSERT(msg_decode.id() == 10086);
                ASSERT(msg_decode.str().compare("hello world") == 0);
                ASSERT(msg_decode.opt() == 10000);
            }

            3.std::fstream
            void testStream()
            {
                //////////////////////////////////////////////////////////////////////////
                // 編碼
                //////////////////////////////////////////////////////////////////////////
                proto::helloworld::HelloWorld msg_encode;
                msg_encode.set_id(10086);
                msg_encode.set_str("hello world");
                msg_encode.set_opt(10000);

                std::fstream output("./msg_bin", std::ios::out | std::ios::trunc | std::ios::binary);
                bool encode_ok = msg_encode.SerializeToOstream(&output);
                ASSERT(encode_ok);
                output.close();

                //////////////////////////////////////////////////////////////////////////
                // 解碼
                //////////////////////////////////////////////////////////////////////////
                std::fstream input("./msg_bin", std::ios::in | std::ios::binary);
                proto::helloworld::HelloWorld msg_decode;
                bool decode_ok = msg_decode.ParseFromIstream(&input);
                ASSERT(decode_ok);

                ASSERT(msg_decode.id() == 10086);
                ASSERT(msg_decode.str().compare("hello world") == 0);
                ASSERT(msg_decode.opt() == 10000);
            }
            以上就是ProtoBuf的基本用法了.


            FlatBuffers

            FlatBuffers支持將ProtoBuf的IDL轉換為自己的IDL,只需要簡單的一行命令:
            flatc.exe --proto Helloworld.proto
            該命令將會生成一個FlatBuffers的IDL文件:Helloworld.fbs.

            Helloworld.fbs它看起來像是這樣的:
            // Generated from Helloworld.proto

            namespace fbs.helloworld;

            table HelloWorld {
              id:int = 0 (id: 0);
              str:string (required, id: 1);
              opt:int = 0 (id: 2);
            }

            // 定義之后將會提供GetHelloWorld,VerifyHelloWorldBuffer,FinishHelloWorldBuffer三個方法.
            root_type HelloWorld;
            這是我基于生成的IDL修改過的.

            我們可以用下面這個bat去生成代碼:
            flatc.exe --cpp -o ../ Helloworld.fbs
            pause
            執行之后,它將在當前目錄的上一層目錄下生成一個代碼文件:Helloworld_generated.h

            使用方法大概是這樣的:
            void testFlatBuffer()
            {
                //////////////////////////////////////////////////////////////////////////
                // 編碼
                //////////////////////////////////////////////////////////////////////////

                flatbuffers::FlatBufferBuilder builder;

                int32_t id = 10086;
                const char *str = "hello world";
                int32_t opt = 10000;

            #if 0
                auto strName = builder.CreateString(str);
                auto root = fbs::helloworld::CreateHelloWorld(builder, id, strName, opt);
            #else
                auto root = fbs::helloworld::CreateHelloWorldDirect(builder, id, str, opt);
            #endif

            #if 0
                builder.Finish(root);
            #else
                FinishHelloWorldBuffer(builder, root);
            #endif

                auto p = builder.GetBufferPointer();
                auto sz = builder.GetSize();

                auto bufferpointer =
                    reinterpret_cast<const char *>(builder.GetBufferPointer());
                std::string buffer;
                buffer.assign(bufferpointer, bufferpointer + builder.GetSize());
                size_t n = buffer.length();

                builder.ReleaseBufferPointer();

                //////////////////////////////////////////////////////////////////////////
                // 解碼
                //////////////////////////////////////////////////////////////////////////
            #if 0
                auto decode = flatbuffers::GetRoot<proto::helloworld::HelloWorld>(buffer.c_str());
            #else
                auto decode = fbs::helloworld::GetHelloWorld(buffer.c_str());
            #endif
                assert(decode->id() == 10086);
                assert( strcmp(decode->str()->c_str(), "hello world") == 0);
                assert(decode->opt() == 10000);
            }



            ByteBuffer
            關于這個嘛,看以前的文章:http://www.shnenglu.com/tx7do/archive/2015/06/12/145865.html
            協議定義如下:
            #include "ByteBuffer.h"

            // 聲明序列化
            #define NET_APPEND(STRUCT_TYPE)\
                static ByteBuffer& operator<<(ByteBuffer& lht, const STRUCT_TYPE& rht)

            // 聲明解序列化
            #define NET_READ(STRUCT_TYPE)\
                static const ByteBuffer& operator>>(const ByteBuffer& lht, STRUCT_TYPE& rht)

            namespace bb
            {
                namespace helloworld
                {

                    struct CMD_HelloWorld
                    {

                        int32            id;        // id
                        std::string        str;    // str
                        int32            opt;    // optional field

                        CMD_HelloWorld()
                        {
                            this->id = 0;
                            this->opt = 0;
                            this->str.clear();
                        }
                    };
                    NET_APPEND(CMD_HelloWorld)
                    {
                        lht << rht.id
                            << rht.str
                            << rht.opt;
                        return lht;
                    };
                    NET_READ(CMD_HelloWorld)
                    {
                        lht >> rht.id
                            >> rht.str
                            >> rht.opt;
                        return lht;
                    };


                }
            }
            使用的代碼是這樣的:
            void testByteBuffer()
            {
                //////////////////////////////////////////////////////////////////////////
                // 編碼
                //////////////////////////////////////////////////////////////////////////
                bb::helloworld::CMD_HelloWorld msg_encode;
                msg_encode.id = 10086;
                msg_encode.str = "hello world";
                msg_encode.opt = 10000;

                ByteBuffer sendBuffer;
                sendBuffer.clear();
                sendBuffer << msg_encode;
                
                auto p = sendBuffer.contents();
                auto sz = sendBuffer.size();
                
                //////////////////////////////////////////////////////////////////////////
                // 解碼
                //////////////////////////////////////////////////////////////////////////
                ByteBuffer recvBuffer;
                recvBuffer.clear();
                recvBuffer.append((uint8*)p, sz);
                    bb::helloworld::CMD_HelloWorld msg_decode;
                recvBuffer >> msg_decode;

                assert(msg_decode.id == 10086);
                assert(strcmp(msg_decode.str.c_str(), "hello world") == 0);
                assert(msg_decode.opt == 10000);
            }


            總結
            相比PB來說,FBS不需要額外的指定一個外部的緩存,它內置了一個緩存,大概這就是它快的緣故吧.
            序列化之后的空間占用結果是:protobuf:19 flatbuffers:48 bytebuffer:20.
            從空間上看,FBS是并不占優啊.
            以前,一直使用的是ByteBuffer,因為簡單,而且無論是從空間上還是時間上都還算劃算.但是要手寫序列化的代碼,相對來說,比較煩人.所以還是PB,FBS這樣的利用IDL自動生成代碼的方式方便.
            PB現在支持幾乎所有語言,是一個相當成熟的解決方案了.
            FBS就目前來說,支持的語言并不多,官方只支持:C++,Java,C#,Go,Python,JS,C,PHP,Ruby.
            PB的IDL各大編輯器幾乎都支持它的語法染色,然而FBS卻并沒有,這個看起來也很讓人蛋疼.
            PB相對慢,但是空間占用小,它更適合外網傳輸,并且對時間并不是那么要求高的應用;
            FBS相對快,但是空間占用較大,它在RPC,內網傳輸,以及對時間要求很高的場景上會很適合,在手機登移動平臺下,計算性能不高的場景下也是適合的.
            總的來說,我要做網游的通訊協議,還是PB更加的適合.
            FBS更適合的是Android,iOS這樣的移動平臺,因為它們對性能要求比較高,使用FBS能夠有效的提高性能.

            posted on 2016-11-20 15:22 楊粼波 閱讀(2791) 評論(0)  編輯 收藏 引用

            国产精品成人99久久久久| 亚洲综合日韩久久成人AV| 国产精品美女久久久| 久久成人国产精品二三区| 久久午夜综合久久| 97久久国产综合精品女不卡| 狠狠色丁香久久婷婷综合五月| 精品一区二区久久久久久久网站| 国产精品久久久久久久午夜片| 伊人久久大香线蕉成人| 久久久WWW成人| 久久线看观看精品香蕉国产| 精品久久久久久综合日本| 日本五月天婷久久网站| 国产成人精品久久一区二区三区av| 久久综合色区| 色偷偷91久久综合噜噜噜噜| 天天综合久久一二三区| 久久99热这里只频精品6| 狠狠色婷婷久久综合频道日韩| 97精品依人久久久大香线蕉97| 亚洲精品无码成人片久久| 久久人妻少妇嫩草AV无码专区| 精品久久久久久无码中文字幕一区| www久久久天天com| 国产精品熟女福利久久AV| 色综合合久久天天给综看| 人妻精品久久无码专区精东影业| 99久久久国产精品免费无卡顿| 久久青青草原综合伊人| 亚洲欧美另类日本久久国产真实乱对白 | 久久超碰97人人做人人爱| 91精品国产91久久久久久青草| 久久精品18| 亚洲国产精品18久久久久久| 久久亚洲国产欧洲精品一| 国产精品久久久香蕉| 93精91精品国产综合久久香蕉| 久久99国产乱子伦精品免费| 狠狠色综合久久久久尤物| 无码任你躁久久久久久久|