• <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>

            牽著老婆滿街逛

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

            Protobuf和FlatBuffers以及ByteBuffer的應(yīng)用

            Protobuf版本號(hào):3.1.0
            FlatBuffers版本號(hào):1.4.0



            Protobuf

            首先來(lái)一發(fā)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
            }

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

            :: /////////////////////////////////////////////////////////////
            ::
            :: 編譯Protobuf協(xié)議
            ::
            :: /////////////////////////////////////////////////////////////
            protoc --version

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

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

            以下列舉序列化到三種目標(biāo)里去的實(shí)例
            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轉(zhuǎn)換為自己的IDL,只需要簡(jiǎn)單的一行命令:
            flatc.exe --proto Helloworld.proto
            該命令將會(huì)生成一個(gè)FlatBuffers的IDL文件:Helloworld.fbs.

            Helloworld.fbs它看起來(lái)像是這樣的:
            // Generated from Helloworld.proto

            namespace fbs.helloworld;

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

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

            我們可以用下面這個(gè)bat去生成代碼:
            flatc.exe --cpp -o ../ Helloworld.fbs
            pause
            執(zhí)行之后,它將在當(dāng)前目錄的上一層目錄下生成一個(gè)代碼文件: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
            關(guān)于這個(gè)嘛,看以前的文章:http://www.shnenglu.com/tx7do/archive/2015/06/12/145865.html
            協(xié)議定義如下:
            #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);
            }


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

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


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            乱亲女H秽乱长久久久| 伊人久久大香线蕉av不变影院| 久久996热精品xxxx| 成人精品一区二区久久久| 四虎亚洲国产成人久久精品| 久久精品国产99国产精品亚洲| 日产精品99久久久久久| 欧美久久精品一级c片片| 无码任你躁久久久久久| 久久久久99精品成人片试看| 国产成人香蕉久久久久| 久久久一本精品99久久精品88| 91精品国产9l久久久久| 四虎亚洲国产成人久久精品| 久久久精品人妻一区二区三区四| 久久久久久一区国产精品| 99久久精品国产一区二区 | 久久男人Av资源网站无码软件| 国产精品99久久久久久人| 久久久久99这里有精品10| 国产精品久久一区二区三区| 伊人色综合久久天天人守人婷 | 色综合合久久天天给综看| 久久A级毛片免费观看| 亚洲伊人久久综合中文成人网| 丰满少妇人妻久久久久久| 午夜精品久久久内射近拍高清| 国产一级做a爰片久久毛片| 欧美日韩精品久久免费| 精品国产婷婷久久久| 久久久久无码精品国产不卡| 怡红院日本一道日本久久| 无码专区久久综合久中文字幕 | 亚洲色婷婷综合久久| 日本久久久久久久久久| 亚洲狠狠综合久久| 亚洲国产美女精品久久久久∴| 午夜精品久久久内射近拍高清| 精品国产青草久久久久福利| 久久亚洲国产中v天仙www| 久久久久99精品成人片直播|