【UNITY3D 遊戲開發之五】Google-protobuf與FlatBuffers資料的序列化和反序列化

ourpush發表於2016-10-16

 關於Protobuf 通過本文的轉載和分享的相關連結,足夠了解使用了,所以這裡不贅述了。但是這裡Himi順便提一下“FlatBuffers” ,它是 Protocol Buffers升級版,其主要區別在於FlatBuffers在訪問資料前不需要解析/拆包這一步。

           這裡分享一個FlatBuffers 的連結,童鞋們也可以去了解下 http://itindex.net/detail/50777-google-flatbuffers-%E5%BC%80%E6%BA%90 .

          最後再多說一句,從同事(之前騰訊的)那裡瞭解到,騰訊也有一套類似的框架 TSF4G,很牛x,聽說FlatBuffers 這種就是參考的TSF4G做的。當然這裡也放出參考連結,有興趣的也可以去了解下:http://djt.qq.com/article/view/298     http://zqted.com/qq-mmog-share-learn.html

 

【以下內容,均為轉載】

★protobuf是啥玩意兒?
為了照顧從沒聽說過的同學,照例先來掃盲一把。
首先,protobuf是一個開源 專案(官方站點在“這裡 ”),而且是後臺很硬的開源專案。網上現有的大部分(至少80%)開源專案,要麼是某人單幹、要麼是幾個閒雜人等合夥搞。而protobuf則不然,它是鼎鼎大名的Google公司開發出來,並且在Google內部久經考驗的一個東東。由此可見,它的作者絕非一般閒雜人等可比。
那這個聽起來牛X的東東到底有啥用處捏?簡單地說,這個東東干的事兒其實和XML 差不多,也就是把某種資料結構的資訊,以某種格式儲存起來。主要用於資料儲存、傳輸協議格式等場合。有同學可能心理犯嘀咕了:放著好好的XML不用,幹嘛重新發明輪子啊?!先別急,後面俺自然會有說道。
話說到了去年(大約是08年7月),Google突然大發慈悲,把這個好東西貢獻給了開源社群。這下,像俺這種喜歡撿現成的傢伙可就有福啦!貌似喜歡撿現成的傢伙還蠻多滴,再加上 Google的號召力,開源後不到一年,protobuf的人氣就已經很旺了。所以俺為了與時俱進,就單獨開個帖子來忽悠一把。

★protobuf有啥特色?
掃盲完了之後,就該聊一下技術 方面的話題了。由於這玩意兒釋出的時間較短(未滿週歲),所以俺接觸的時間也不長。今天在此是先學現賣,列位看官多多包涵 :-)

◇效能好/效率高
現在,俺就來說說Google公司為啥放著好端端的XML不用,非要另起爐灶,重新造輪子。一個根本的原因是XML效能不夠好。
先說時間開銷:XML格式化(序列化)的開銷倒還好;但是XML解析(反序列化)的開銷就不敢恭維啦。俺之前經常碰到一些時間效能很敏感的場合,由於不堪忍受XML解析的速度,棄之如敝履。
再來看空間開銷:熟悉XML語法的同學應該知道,XML格式為了有較好的可讀性,引入了一些冗餘的文字資訊。所以空間開銷也不是太好(不過這點缺點,俺不常碰到)。
由於Google公司賴以吹噓的就是它的海量資料和海量處理能力。對於幾十萬、上百萬機器的叢集,動不動就是PB級的資料量,哪怕效能稍微提高 0.1% 也是相當可觀滴。所以Google自然無法容忍XML在效能上的明顯缺點。再加上Google從來就不缺造輪子的牛人,所以protobuf也就應運而生了。
Google對於效能的偏執,那可是出了名的。所以,俺對於Google搞出來protobuf是非常滴放心,效能上不敢說是最好,但肯定不會太差。

◇程式碼 生成機制
除了效能好,程式碼生成機制是主要吸引俺的地方。為了說明這個程式碼生成機制,俺舉個例子。
比如有個電子商務的系統(假設用C++實現),其中的模組A需要傳送大量的訂單資訊給模組B,通訊的方式使用socket。
假設訂單包括如下屬性:
--------------------------------
時間:time(用整數表示)
客戶id:userid(用整數表示)
交易金額:price(用浮點數表示)
交易的描述:desc(用字串表示)
--------------------------------
如果使用protobuf實現,首先要寫一個proto檔案(不妨叫Order.proto),在該檔案中新增一個名為”Order”的message結構,用來描述通訊協議中的結構化資料。該檔案的內容大致如下:

--------------------------------

message Order
{
required int32 time = 1;
required int32 userid = 2;
required float price = 3;
optional string desc = 4;
}

--------------------------------
然後,使用protobuf內建的編譯器編譯 該proto。由於本例子的模組是C++,你可以通過protobuf編譯器的命令列引數(看“這裡 ”),讓它生成C++語言的“訂單包裝類”。(一般來說,一個message結構會生成一個包裝類)
然後你使用類似下面的程式碼來序列化/解析該訂單包裝類:
--------------------------------

// 傳送方

Order order;
order.set_time(XXXX);
order.set_userid(123);
order.set_price(100.0f);
order.set_desc(“a test order”);

string sOrder;
order.SerailzeToString(&sOrder);

// 然後呼叫某種socket的通訊庫把序列化之後的字串傳送出去
// ……

--------------------------------

// 接收方

string sOrder;
// 先通過網路通訊庫接收到資料,存放到某字串sOrder
// ……

Order order;
if(order.ParseFromString(sOrder))  // 解析該字串
{
cout << “userid:” << order.userid() << endl
<< “desc:” << order.desc() << endl;
}
else
{
cerr << “parse error!” << endl;
}

--------------------------------
有了這種程式碼生成機制,開發人員再也不用吭哧吭哧地編寫那些協議解析的程式碼了(幹這種活是典型的吃力不討好)。
萬一將來需求發生變更,要求給訂單再增加一個“狀態”的屬性,那隻需要在Order.proto檔案中增加一行程式碼。對於傳送方(模組A),只要增加一行設定狀態的程式碼;對於接收方(模組B)只要增加一行讀取狀態的程式碼。哇塞,簡直太輕鬆了!
另外,如果通訊雙方使用不同的程式語言來實現,使用這種機制可以有效確保兩邊的模組對於協議的處理是一致的。
順便跑題一下。
從某種意義上講,可以把proto檔案看成是描述通訊協議的規格說明書(或者叫介面規範)。這種伎倆其實老早就有了,搞過微軟的COM程式設計或者接觸過CORBA的同學,應該都能從中看到IDL(詳細解釋看“這裡 ”)的影子。它們的思想是相通滴。

◇支援“向後相容”和“向前相容”
還是拿剛才的例子來說事兒。為了敘述方便,俺把增加了“狀態”屬性的訂單協議成為“新版本”;之前的叫“老版本”。
所謂的“向後相容”(backward compatible),就是說,當模組B升級了之後,它能夠正確識別模組A發出的老版本的協議。由於老版本沒有“狀態”這個屬性,在擴充協議時,可以考慮把“狀態”屬性設定成非必填 的,或者給“狀態”屬性設定一個預設值(如何設定預設值,參見“這裡 ”)。
所謂的“向前相容”(forward compatible),就是說,當模組A升級了之後,模組B能夠正常識別模組A發出的新版本的協議。這時候,新增加的“狀態”屬性會被忽略。
“向後相容”和“向前相容”有啥用捏?俺舉個例子:當你維護一個很龐大的分散式系統時,由於你無法同時 升級所有 模組,為了保證在升級過程中,整個系統能夠儘可能不受影響,就需要儘量保證通訊協議的“向後相容”或“向前相容”。

◇支援多種程式語言
俺開博以來點評 的幾個開源專案(比如“Sqlite ”、“cURL ”),都是支援很多種 程式語言滴,這次的protobuf也不例外。在Google官方釋出的原始碼中包含了C++、Java 、Python三種語言(正好也是俺最常用的三種,真爽)。如果你平時用的就是這三種語言之一,那就好辦了。
假如你想把protobuf用於其它語言,咋辦捏?由於Google一呼百應的號召力,開源社群對protobuf響應踴躍,近期冒出很多其它程式語言的版本(比如ActionScript、C#、Lisp、Erlang、Perl、PHP 、Ruby等),有些語言還同時搞出了多個開源的專案。具體細節可以參見“這裡 ”。
不過俺有義務提醒一下在座的各位同學。如果你考慮把protobuf用於上述這些語言,一定認真評估對應的開源庫。因為這些開源庫不是Google官方提供的、而且出來的時間還不長。所以,它們的質量、效能等方面可能還有欠缺。

★protobuf有啥缺陷?
前幾天剛剛在“光環效應 ”的帖子裡強調了“要同時評估優點和缺點”。所以俺最後再來批判一下這玩意兒的缺點。
◇應用 不夠廣
由於protobuf剛公佈沒多久,相比XML而言,protobuf還屬於初出茅廬。因此,在知名度、應用廣度等方面都遠不如XML。由於這個原因,假如你設計的系統需要提供若干對外的介面給第三方系統呼叫,俺奉勸你暫時不要考慮protobuf格式。
◇二進位制格式導致可讀性差
為了提高效能,protobuf採用了二進位制格式進行編碼。這直接導致了可讀性差的問題(嚴格地說,是沒有可讀性)。雖然protobuf提供了TextFormat這個工具類(文件在“這裡 ”),但終究無法徹底解決此問題。
可讀性差的危害,俺再來舉個例子。比如通訊雙方如果出現問題,極易導致扯皮(都不承認自己有問題,都說是對方的錯)。俺對付扯皮的一個簡單方法 就是直接抓包並dump成log,能比較容易地看出錯誤在哪一方。但是protobuf的二進位制格式,導致你抓包並直接dump出來的log難以看懂。
◇缺乏自描述
一般來說,XML是自描述的,而protobuf格式則不是。給你一段二進位制格式的協議內容,如果不配合相應的proto檔案,那簡直就像天書一般。
由於“缺乏自描述”,再加上“二進位制格式導致可讀性差”。所以在配置檔案方面,protobuf是肯定無法取代XML的地位滴。

★為什麼俺會用上protobuf?
俺自從前段時間接觸了protobuf之後,就著手把俺負責的產品中的部分資料傳輸協議替換成protobuf。可能有同學會問,和protobuf類似的東東也有不少,為啥獨獨相中protobuf捏?由於今天寫的篇幅已經蠻長了,俺賣個關子,把這個話題留到“生產者/消費者模式[5]:如何選擇傳輸協議及格式?”。俺會在後續的這個帖子裡對比各種五花八門的協議格式,並談談俺的淺見。

 

1.GoogleProtoBuf開發者指南  http://wenku.baidu.com/link?url=IlqKZ0Uc-NVs1KmGlQBw6IoRf6UTIln8QBEhtZ-5qWwAm6xcGYF3z6nMzaIDb-wA9R2ULnqh4XbXpFGXx6rqdKb41h8B_hxGWe0vYlp9-0W

2.   .protobuf檔案轉成.cs檔案方法      http://www.cnblogs.com/pctzhang/archive/2012/08/30/2663804.html

3. lua下使用protobuf   http://www.thinksaas.cn/group/topic/276365/

4. Android與PC,C#與Java 利用protobuf 進行無障礙通訊【Socket】   http://www.cnblogs.com/TerryBlog/archive/2011/04/23/2025654.html

5. protobuf 小示例 http://www.cnblogs.com/sifenkesi/p/4045392.html

轉載自【黑米GameDev街區】 原文連結: http://www.himigame.com/unity3d-game/1607.html 
 


【關於我們】

每天名企社招內推(微信眾號ourpush),專注於國內各大網際網路公司社會招聘內推。每天更新最新網際網路名企(包括但不限於網易遊戲、BAT、網易網際網路、小米、京東、樂視、攜程等名企)內推資訊,有技術崗、有產品崗、有運營崗、有設計崗、有互動崗、有銷售崗,更有其他N多相關崗位!更多內推資訊請掃描以下二維碼關注查閱。





相關文章