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