目錄
1.什么是protobuffer?
protobuffer是一種靈活,高效,自動化的機制,用於序列化結構化數據 - 想想XML,但更小,更快,更簡單。您可以定義數據的結構化時間,然后可以使用特殊生成的源代碼輕松地在各種數據流中使用各種語言編寫和讀取結構化數據。您甚至可以更新數據結構,而不會破壞根據“舊”格式編譯的已部署程序。
2.protobuffer是如何工作的?
您可以通過在.proto文件中定義協議緩沖區消息類型來指定您希望如何構建序列化信息。每個協議緩沖區消息都是一個小的邏輯信息記錄,包含一系列名稱 - 值對。以下.proto是定義包含有關人員信息的消息的文件的一個非常基本的示例:
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
如您所見,消息格式很簡單 - 每種消息類型都有一個或多個唯一編號的字段,每個字段都有一個名稱和一個值類型,其中值類型可以是數字(整數或浮點數),布爾值,字符串,字節,甚至(如上例所示)其他協議緩沖區消息類型,允許您分層次地構建數據。您可以指定可選字段,必填字段和重復字段。您可以.proto在Protocol Buffer Language Guide中找到有關編寫文件的更多信息。
一旦定義了消息,就可以在.proto文件上運行應用程序語言的協議緩沖區編譯器來生成數據訪問類。這些為每個字段(如name()和set_name())提供了簡單的訪問器,以及將整個結構序列化/解析為原始字節的方法 - 例如,如果您選擇的語言是C ++,則在上面的示例中運行編譯器將生成了Person類。然后,您可以在應用程序中使用此類來填充,序列化和檢索Person協議緩沖區消息。然后你可以寫一些這樣的代碼:
Person person; person.set_name("John Doe"); person.set_id(1234); person.set_email("jdoe@example.com"); fstream output("myfile", ios::out | ios::binary); person.SerializeToOstream(&output);
然后可以這樣讀入消息
1 fstream input("myfile", ios::in | ios::binary); 2 Person person; 3 person.ParseFromIstream(&input); 4 cout << "Name: " << person.name() << endl; 5 cout << "E-mail: " << person.email() << endl;
您可以在消息格式中添加新字段,而不會破壞向后兼容性; 舊的二進制文件在解析時只是忽略新字段。因此,如果您的通信協議使用協議緩沖區作為其數據格式,則可以擴展協議,而無需擔心破壞現有代碼。
您將在API參考部分找到有關使用生成的協議緩沖區代碼的完整參考,您可以在協議緩沖區編碼中找到有關如何編碼協議緩沖區消息的更多信息。
3.為什么不使用XML?
對於序列化結構化數據,protobuffer比XML具有許多優點。protobuffer:
- 更簡單
- 比小3到10倍
- 快20到100倍
- 不那么曖昧
- 生成更易於以編程方式使用的數據訪問類
例如,假設你想要定義一個擁有一個name和email的person。在XML中,您需要:
1 <person> 2 <name>John Doe</name> 3 <email>jdoe@example.com</email> 4 </person>
而使用相應的protobuffer是:
1 # Textual representation of a protocol buffer. 2 # This is *not* the binary format used on the wire. 3 person { 4 name: "John Doe" 5 email: "jdoe@example.com" 6 }
當此消息被編碼為protobuffer二進制格式(上面的文本格式只是用於調試和編輯的方便的人類可讀表示)時,它可能長達28個字節並且需要大約100-200納秒來解析。如果刪除空格,XML版本至少為69個字節,並且需要大約5,000-10,000納秒才能解析。
此外操作protobuffer數據更容易:
1 cout << "Name: " << person.name() << endl; 2 cout << "E-mail: " << person.email() << endl;
如果你是用xml,可能是這個樣子:
1 cout << "Name: " 2 << person.getElementsByTagName("name")->item(0)->innerText() 3 << endl; 4 cout << "E-mail: " 5 << person.getElementsByTagName("email")->item(0)->innerText() 6 << endl;
但是,protobuffer並不總是比XML更好的解決方案 - 例如,protobuffer不是使用標記(例如HTML)對基於文本的文檔建模的好方法,因為您無法輕松地將結構與文本交錯。此外,XML是人類可讀的和人類可編輯的; XML在某種程度上也是自我描述的。只有擁有消息定義(.proto文件)時,protobuffer才有意義。
