使用Google Protocol Bufffers進行通訊(Ruby & C)
最近專案中需要用到Google 的 proto buffer作為一種跨平臺通訊的協議。首先感謝楓 和 未 的部落格,讓我對這個協議有了一些初步的理解。
協議的由來
在後臺需要與多種終端如iPhone,Android,Web或者WinPhone之類的不同平臺作通訊的時候,常常需要使用一種中間的通訊協議,並且使用通用資料型別如XML。現在專案中的裝置底層是用c語言完成的,我們服務端的語言是ruby,中間層是IOS或者Andriod的裝置。
Protocol Buffers(以下簡稱protobuf)就是類似於XML這樣的東西,可以在後臺與多終端間進行通訊,但是比它要遠強大的多。
Protobuf由Google出品,08年的時候Google把這個專案開源了,截至發稿已發展到2.5.0版本,官方支援C++,Java和Python三種語言,但是由於其設計得很簡單,所以衍生出很多第三方的支援,基本上常用的PHP,C,ruby等多種語言都已有第三方的庫。
Protobuf的優勢
首先我們來比較和XML來比較一下,其實最主要的優勢就是它更簡單了。
一個XML檔案我們編寫的時候需要定義各種各種的節點,而Proto檔案則使用Google定義的有點像Java的語言來編寫,簡潔很多。
XML長得像這樣,看起來很冗餘,因為要加很多標籤:
<person>
<name>John Doe</name>
<email>jdoe@example.com</email>
</person>
而我們的proto檔案則長這樣:
# Textual representation of a protocol buffer.
# This is *not* the binary format used on the wire.
person {
name: "John Doe"
email: "jdoe@example.com"
}
其次是快了。proto檔案是給程式猿閱讀的時候用的,真正傳輸的時候是序列化的二進位制資料,比起XML要小得多,解析起來也快得多。
第三是可以直接生成供程式使用的類。XML檔案接收後我們還得手工去解析然後轉化為可以使用的物件,但是PB檔案接收後,PB的庫就已經幫我們轉化為對應的資料類了。
Protobuf主要分為兩個部分,一是編譯器protoc,一是分包組包所用到的庫。
編譯器是用來編譯proto檔案為目標語言的,比如一個上面那個 Person.proto 檔案,我可以用 protoc 直接編譯成C++類 Person,用的時候就很方便了:
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
使用
我們現在的後臺開發中,主要用到的是Ruby on Rails, 所以我們先來著重看一看protobuf在Rails中的使用方法。
- 定義好proto的檔案
package Tutorial;
message Source {
required string title = 1;
required string description = 2;
optional int id = 3;
}
message SourceAllResponse {
required uint32 count = 1;
repeated Source source_list = 2;
}
- 編譯成對應語言
定義完proto檔案後,使用官方的 protoc 可以對其進行編譯。下載地址在: https://code.google.com/p/protobuf/downloads/list
如果是 Mac OS X 或者 Linux ,需要下載官方的原始碼,解壓後根據官方的 README.txt 裡的說明:
$ ./configure
$ make
$ make check
$ make install
- Ruby的用法:
待補充
Protobuf 語法定義
首先我們再來定義一個proto檔案,結構如下:
message Article {
required int32 article_id=1;
optional string article_excerpt=2;
repeated string article_picture=3;
}
上面我們主要定義了一個訊息,這個訊息包括文章ID,文章摘要,文章圖片。下面給出訊息定義的相關說明:
名稱 | 定義 |
---|---|
message | 是訊息定義的關鍵字 |
required | 表示這個欄位必須的,必須在序列化的時候被賦值 |
optional | 代表這個欄位是可選的,可以為0個或1個但不能大於1個 |
repeated | 則代表此欄位可以被重複任意多次包括0次 |
int32和string | 欄位的型別,後面是我們定義的欄位名 |
最後的1,2,3則是代表每個欄位的一個唯一的編號標籤,在同一個訊息裡不可以重複。這些編號標籤用與在訊息二進位制格式中標識你的欄位,並且訊息一旦定義就不能更改。需要說明的是標籤在1到15範圍的採用一個位元組進行編碼。所以通常將標籤1到15用於頻繁發生的訊息欄位。編號標籤大小的範圍是1到229,此外不能使用protobuf系統預留的編號標籤(19000 -19999)。當然protobuf支援更多的型別,比如bool, double, float, emun, 也可以是其他定義過的訊息型別譬如前面的訊息Article。
下面讓我們定義一個資料比較多的article.proto檔案來再次說明下proto語法的相關內容,起碼通過列子可以更直觀的感受:
syntax = "proto3";
package zji.proto;
message Article {
required int32 article_id = 1;
optional string article_excerpt = 2;
repeated string article_picture = 3;
optional int32 article_pagecount = 4 [default = 0];
enum ArticleType {
NOVEL = 0;
PROSE = 1;
PAPER = 2;
POETRY = 3;
}
optional ArticleType article_type = 5 [default = NOVEL];
message Author {
required string name = 1; //作者的名字
optional string phone = 2;
}
optional Author author = 6;
repeated int32 article_numberofwords = 7 [packed=true];
reserved 9, 10, 12 to 15;
extensions 100 to 1000;
}
extend Article {
optional int32 followers_count = 101;
optional int32 likes_count= 102;
}
message Other {
optional string other_info = 1;
oneof test_oneof {
string code1 = 2;
string code2 = 3;
}
}
reserved關鍵字: 主要用於保留相關編號標籤。這麼做的目的就是防止更新proto檔案刪除了某些欄位,而未來的使用者定義新的欄位時重新使用了該編號標籤。這會引起一些問題,比如在獲取老版本的訊息時,會引起譬如資料衝突等一些隱藏的bug,所以一定要用reserved標記這些編號標籤以保證不會被使用。其實對這個關鍵字的用法理解得並不是很深刻,後面有機會用到我們再補充。
extent關鍵字:當我們需要對訊息進行擴充套件的時候,我們可以用extensions關鍵字來定義一些編號標籤供第三方擴充套件。這樣的好處是不需要修改原來的訊息格式。就像上面proto檔案,我們用extend關鍵字來擴充套件。只要擴充套件的欄位編號標籤在extensions定義的範圍裡。
oneof關鍵字: 待補充
packed=true的作用: 對於基本數值型別,由於歷史原因,不能被protobuf更有效的encode。所以在新的程式碼中使用packed=true可以更加有效率地encode。注意packed只能用於repeated 數值型別的欄位。不能用於string型別的欄位。
相關文章
- C++使用libcurl進行http通訊C++HTTP
- C# 使用SuperSocket的FixedHeaderReceiveFilter進行通訊C#HeaderFilter
- 使用SuperSocket的FixedHeaderReceiveFilter進行通訊HeaderFilter
- C#使用SendMessage進行程序間通訊C#行程
- 使用UDP如何進行網路通訊UDP
- google protocol buffer——protobuf的問題及改進一GoProtocol
- google protocol buffer——protobuf的問題和改進2GoProtocol
- C#語言下使用gRPC、protobuf(Google Protocol Buffers)實現檔案傳輸C#RPCGoProtocol
- 在 Laravel 中使用 Workerman 進行 socket 通訊Laravel
- google protocol buffer——protobuf的基本使用和模型分析GoProtocol模型
- 通過串列埠進行通訊 :串列埠
- Android Socket連線,使用Socket進行通訊(Android)Android
- google protocol buffer——protobuf的使用特性及編碼原理GoProtocol
- 使用 Linux 命令列與其他使用者進行通訊Linux命令列
- 【USB】C#使用HID通訊C#
- 張高興的 .NET Core IoT 入門指南:(三)使用 I2C 進行通訊
- C++ 用libcurl庫進行http通訊網路程式設計C++HTTP程式設計
- linux下 libusb使用--開啟usb裝置進行通訊Linux
- 在Dubbo-go中使用TLS加密進行安全通訊GoTLS加密
- 使用Modbus4J進行RTU模式串列埠通訊模式串列埠
- 前端後臺以及遊戲中使用Google Protocol Buffer詳解前端遊戲GoProtocol
- AvaloniaTCP-v1.0.0:學習使用Avalonia/C#進行TCP通訊的一個簡單DemoTCPC#
- 採用管道進行通訊的例子
- 通過JNI對C++進行封裝C++封裝
- google protocol buffer——protobuf的編碼原理二GoProtocol
- 如何使用Java串列埠進行資料通訊及應用案例Java串列埠
- $attrs 與 $listeners 進行「巢狀元件」通訊巢狀元件
- 利用橢圓曲線進行加密通訊加密
- C#如何開發透過USB進行串列埠通訊的Androud上位機C#串列埠
- 使用 C-Reduce 進行除錯除錯
- 一文搞懂如何使用Node.js進行TCP網路通訊Node.jsTCP
- Netty使用Google Protocol Buffer完成伺服器高效能資料傳輸NettyGoProtocol伺服器
- Android C++層使用Binder通訊的方法AndroidC++
- 【Ruby】創藍253雲通訊平臺國際簡訊API介面DEMOAPI
- 簡單的Java實現Netty進行通訊JavaNetty
- 張高興的 .NET Core IoT 入門指南:(四)使用 SPI 進行通訊
- 還在用JSON? Google Protocol Buffers 更快更小 (實踐篇)JSONGoProtocol
- 還在用JSON? Google Protocol Buffers 更快更小 (原理篇)JSONGoProtocol