http://www.cppblog.com/woaidongmao/archive/2009/06/23/88391.html
http://blog.sina.com.cn/s/blog_abea023b0101dxce.html
linux中開發的所有軟件或者以常規操作方式:1 運行
如何編譯protobuf 方法是protoc addressbook.proto --cpp_out ./
message PhoneNumber {
Protobuf消息定義
消息由至少一個字段組合而成,類似於C語言中的結構。每個字段都有一定的格式。
字段格式:限定修飾符① | 數據類型② | 字段名稱③ | = | 字段編碼值④ | [字段默認值⑤]
①.限定修飾符包含 required\optional\repeated
Required: 表示是一個必須字段,必須相對於發送方,在發送消息之前必須設置該字段的值,對於接收方,必須能夠識別該字段的意思。發送之前沒有設置required字段或者無法識別required字段都會引發編解碼異常,導致消息被丟棄。
Optional:表示是一個可選字段,可選對於發送方,在發送消息時,可以有選擇性的設置或者不設置該字段的值。對於接收方,如果能夠識別可選字段就進行相應的處理,如果無法識別,則忽略該字段,消息中的其它字段正常處理。---因爲optional字段的特性,很多接口在升級版本中都把後來添加的字段都統一的設置爲optional字段,這樣老的版本無需升級程序也可以正常的與新的軟件進行通信,只不過新的字段無法識別而已,因爲並不是每個節點都需要新的功能,因此可以做到按需升級和平滑過渡。
Repeated:表示該字段可以包含0~N個元素。其特性和optional一樣,但是每一次可以包含多個值。可以看作是在傳遞一個數組的值。
②.數據類型
Protobuf定義了一套基本數據類型。幾乎都可以映射到C++\Java等語言的基礎數據類型.
protobuf 數據類型 |
描述 |
打包 |
C++語言映射 |
bool |
布爾類型 |
1字節 |
bool |
double |
64位浮點數 |
N |
double |
float |
32爲浮點數 |
N |
float |
int32 |
32位整數、 |
N |
int |
uin32 |
無符號32位整數 |
N |
unsigned int |
int64 |
64位整數 |
N |
__int64 |
uint64 |
64爲無符號整 |
N |
unsigned __int64 |
sint32 |
32位整數,處理負數效率更高 |
N |
int32 |
sing64 |
64位整數 處理負數效率更高 |
N |
__int64 |
fixed32 |
32位無符號整數 |
4 |
unsigned int32 |
fixed64 |
64位無符號整數 |
8 |
unsigned __int64 |
sfixed32 |
32位整數、能以更高的效率處理負數 |
4 |
unsigned int32 |
sfixed64 |
64爲整數 |
8 |
unsigned __int64 |
string |
只能處理 ASCII字符 |
N |
std::string |
bytes |
用於處理多字節的語言字符、如中文 |
N |
std::string |
enum |
可以包含一個用戶自定義的枚舉類型uint32 |
N(uint32) |
enum
|
message |
可以包含一個用戶自定義的消息類型 |
N |
object of class |
N 表示打包的字節並不是固定。而是根據數據的大小或者長度。
例如int32,如果數值比較小,在0~127時,使用一個字節打包。
關於枚舉的打包方式和uint32相同。
關於message,類似於C語言中的結構包含另外一個結構作爲數據成員一樣。
關於 fixed32 和int32的區別。fixed32的打包效率比int32的效率高,但是使用的空間一般比int32多。因此一個屬於時間效率高,一個屬於空間效率高。根據項目的實際情況,一般選擇fixed32,如果遇到對傳輸數據量要求比較苛刻的環境,可以選擇int32.
③.字段名稱
字段名稱的命名與C、C++、Java等語言的變量命名方式幾乎是相同的。
protobuf建議字段的命名採用以下劃線分割的駝峯式。例如 first_name 而不是firstName.
④.字段編碼值
有了該值,通信雙方纔能互相識別對方的字段。當然相同的編碼值,其限定修飾符和數據類型必須相同。
編碼值的取值範圍爲 1~2^32(4294967296)。
其中 1~15的編碼時間和空間效率都是最高的,編碼值越大,其編碼的時間和空間效率就越低(相對於1-15),當然一般情況下相鄰的2個值編碼效率的是相同的,除非2個值恰好實在4字節,12字節,20字節等的臨界區。比如15和16.
1900~2000編碼值爲Google protobuf 系統內部保留值,建議不要在自己的項目中使用。
protobuf 還建議把經常要傳遞的值把其字段編碼設置爲1-15之間的值。
消息中的字段的編碼值無需連續,只要是合法的,並且不能在同一個消息中有字段包含相同的編碼值。
建議:項目投入運營以後涉及到版本升級時的新增消息字段全部使用optional或者repeated,儘量不實用required。如果使用了required,需要全網統一升級,如果使用optional或者repeated可以平滑升級。
⑤.默認值。當在傳遞數據時,對於required數據類型,如果用戶沒有設置值,則使用默認值傳遞到對端。當接受數據是,對於optional字段,如果沒有接收到optional字段,則設置爲默認值。
關於import
protobuf 接口文件可以像C語言的h文件一個,分離爲多個,在需要的時候通過 import導入需要對文件。其行爲和C語言的#include或者java的import的行爲大致相同。
關於package
避免名稱衝突,可以給每個文件指定一個package名稱,對於java解析爲java中的包。對於C++則解析爲名稱空間。
關於message
支持嵌套消息,消息可以包含另一個消息作爲其字段。也可以在消息內定義一個新的消息。
關於enum
枚舉的定義和C++相同,但是有一些限制。
枚舉值必須大於等於0的整數。
使用分號(;)分隔枚舉變量而不是C++語言中的逗號(,)
eg.
enum VoipProtocol
{
}
1
歡迎來到protocol buffer的開發者指南文檔,一種語言無關、平臺無關、擴展性好的用於通信協議、數據存儲的結構化數據串行化方法。
本文檔面向希望使用protocol buffer的Java、C++或Python開發者。這個概覽介紹了protocol buffer,並告訴你如何開始,你隨後可以跟隨編程指導( http://code.google.com/apis/protocolbuffers/docs/tutorials.html )深入瞭解protocol buffer編碼方式( http://code.google.com/apis/protocolbuffers/docs/encoding.html )。API參考文檔( http://code.google.com/apis/protocolbuffers/docs/reference/overview.html )同樣也是提供了這三種編程語言的版本,不夠協議語言( http://code.google.com/apis/protocolbuffers/docs/proto.html )和樣式( http://code.google.com/apis/protocolbuffers/docs/style.html )指導都是編寫 .proto 文件。
1.1
ProtocolBuffer是用於結構化數據串行化的靈活、高效、自動的方法,有如XML,不過它更小、更快、也更簡單。你可以定義自己的數據結構,然後使用代碼生成器生成的代碼來讀寫這個數據結構。你甚至可以在無需重新部署程序的情況下更新數據結構。
1.2
你首先需要在一個 .proto 文件中定義你需要做串行化的數據結構信息。每個ProtocolBuffer信息是一小段邏輯記錄,包含一系列的鍵值對。這裏有個非常簡單的 .proto 文件定義了個人信息:
message Person {
}
有如你所見,消息格式很簡單,每個消息類型擁有一個或多個特定的數字字段,每個字段擁有一個名字和一個值類型。值類型可以是數字(整數或浮點)、布爾型、字符串、原始字節或者其他ProtocolBuffer類型,還允許數據結構的分級。你可以指定可選字段,必選字段和重複字段。你可以在( http://code.google.com/apis/protocolbuffers/docs/proto.html )找到更多關於如何編寫 .proto 文件的信息。
一旦你定義了自己的報文格式(message),你就可以運行ProtocolBuffer編譯器,將你的 .proto文件編譯成特定語言的類。這些類提供了簡單的方法訪問每個字段(像是 query() 和 set_query() ),像是訪問類的方法一樣將結構串行化或反串行化。例如你可以選擇C++語言,運行編譯如上的協議文件生成類叫做 Person 。隨後你就可以在應用中使用這個類來串行化的讀取報文信息。你可以這麼寫代碼:
Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("[email protected]");
fstream.output("myfile",ios::out | ios::binary);
person.SerializeToOstream(&output);
然後,你可以讀取報文中的數據:
fstream input("myfile",ios::in | ios:binary);
Person person;
person.ParseFromIstream(&input);
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
你可以在不影響向後兼容的情況下隨意給數據結構增加字段,舊有的數據會忽略新的字段。所以如果使用ProtocolBuffer作爲通信協議,你可以無須擔心破壞現有代碼的情況下擴展協議。
你可以在API參考( http://code.google.com/apis/protocolbuffers/docs/reference/overview.html )中找到完整的參考,而關於ProtocolBuffer的報文格式編碼則可以在( http://code.google.com/apis/protocolbuffers/docs/encoding.html )中找到。
1.3
ProtocolBuffer擁有多項比XML更高級的串行化結構數據的特性,ProtocolBuffer:
·
·
·
·
·
例如,讓我們看看如何在XML中建模Person的name和email字段:
對應的ProtocolBuffer報文則如下:
#ProtocolBuffer的文本表示
#這不是正常時使用的二進制數據
person {
}
當這個報文編碼到ProtocolBuffer的二進制格式( http://code.google.com/apis/protocolbuffers/docs/encoding.html )時(上面的文本僅用於調試和編輯),它只需要28字節和100-200ns的解析時間。而XML的版本需要69字節(除去空白)和5000-10000ns的解析時間。
當然,操作ProtocolBuffer也很簡單:
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
而XML的你需要:
cout << "Name: "
cout << "E-mail: "
當然,ProtocolBuffer並不是在任何時候都比XML更合適,例如ProtocolBuffer無法對一個基於標記文本的文檔建模,因爲你根本沒法方便的在文本中插入結構。另外,XML是便於人類閱讀和編輯的,而ProtocolBuffer則不是。還有XML是自解釋的,而 ProtocolBuffer僅在你擁有報文格式定義的 .proto 文件時纔有意義。
1.4
下載包( http://code.google.com/p/protobuf/downloads/ ),包含了Java、Python、C++的ProtocolBuffer編譯器,用於生成你需要的IO類。構建和安裝你的編譯器,跟隨README的指令就可以做到。
一旦你安裝好了,就可以跟着編程指導( http://code.google.com/apis/protocolbuffers/docs/tutorials.html )來選擇語言-隨後就是使用ProtocolBuffer創建一個簡單的應用了。
1.5
ProtocolBuffer最初是在Google開發的,用以解決索引服務器的請求、響應協議。在使用ProtocolBuffer之前,有一種格式用以處理請求和響應數據的編碼和解碼,並且支持多種版本的協議。而這最終導致了醜陋的代碼,有如:
if (version==3) {
}else if (version>4) {
}
通信協議因此變得越來越複雜,因爲開發者必須確保,發出請求的人和接受請求的人必須同時兼容,並且在一方開始使用新協議時,另外一方也要可以接受。
ProtocolBuffer設計用於解決這一類問題:
·
·
然而用戶仍然需要手寫解析代碼。
隨着系統的演化,他需要一些其他的功能:
·
·
·
ProtocolBuffer現在已經是Google的混合語言數據標準了,現在已經正在使用的有超過48,162種報文格式定義和超過12,183個 .proto 文件。他們用於RPC系統和持續數據存儲系統。
2
本指導描述瞭如何使用ProtocolBuffer語言來定義結構化數據類型,包括 .proto 文件的語法和如何生成存取類。
這是一份指導手冊,一步步的例子使用文檔中的多種功能,查看入門指導( http://code.google.com/apis/protocolbuffers/docs/tutorials.html )選擇你的語言。
本文檔提供了 .proto 文件的代碼風格指導。按照慣例,你將會,你將會生成一些便於閱讀和一致的ProtocolBuffer定義文件。
3.1
使用駱駝風格的大小寫命名,即單詞首字母大寫,來做消息名。使用GNU的全部小寫,使用下劃線分隔的方式定義字段名:
message SongServerRequest {
}
使用這種命名方式得到的名字如下:
C++:
Java:
3.2
使用駱駝風格做枚舉名,而用全部大寫做值的名字:
enum Foo {
}
每個枚舉值最後以分號結尾,而不是逗號。
3.3
如果你的 .proto 文件定義了RPC服務,你可以使用駱駝風格:
service FooService {
}
4
本文檔描述了ProtocolBuffer的串行化二進制數據格式定義。你如果僅僅是在應用中使用ProtocolBuffer,並不需要知道這些,但是這些會對你定義高效的格式有所幫助。
7
本指南給Python程序員一個快速使用的ProtocolBuffer的指導。通過一些簡單的例子來在應用中使用ProtocolBuffer,它向你展示瞭如何:
·
·
·
這並不是一個在Python中使用ProtocolBuffer的完整指導。更多細節請參考手冊信息,查看語言指導( http://code.google.com/apis/protocolbuffers/docs/proto.html ),Python API( http://code.google.com/apis/protocolbuffers/docs/reference/python/index.html ),和編碼手冊( http://code.google.com/apis/protocolbuffers/docs/encoding.html )。
7.1
下面的例子”地址本”應用用於讀寫人的聯繫信息。每個人有name、ID、email,和聯繫人電話號碼。
如何串行化和讀取結構化數據呢?有如下幾種問題:
·
·
·
ProtocolBuffer提供了靈活、高效、自動化的方法來解決這些問題。通過ProtocolBuffer,只需要寫一個 .proto 數據結構描述文件,就可以編譯到幾種語言的自動編碼解碼類。生成的類提供了setter和getter方法來控制讀寫細節。最重要的是 ProtocolBuffer支持後期擴展協議,而又確保舊格式可以兼容。
7.2
源碼發行包中已經包含了,在”example”文件夾。
7.3
想要創建你的地址本應用,需要開始於一個 .proto 文件。定義一個 .proto 文件很簡單:添加一個消息到數據結構,然後指定一個和一個類型到每一個字段,如下是本次例子使用的addressbook.proto
package tutorial;
message Person {
}
message AddressBook {
}
有如你所見的,語法類似於C++或Java。讓我們分塊理解他們。
@waiting …
7.4
現在已經擁有了 .proto 文件,下一步就是編譯生成相關的訪問類。運行編譯器 protoc 編譯你的 .proto 文件。
1.
2.
protoc -I=$SRC_DIR --python_out=$DST_DIR addressbook.proto
因爲需要使用Python類,所以 –python_out 選項指定了特定的輸出語言。
這個步驟會生成 addressbook_pb2.py 到目標目錄。
7.5
不像生成的C++和Java代碼,Python生成的類並不會直接爲你生成存取數據的代碼。而是(有如你在addressbook_pb2.py 中見到的)生成消息描述、枚舉、和字段,還有一些神祕的空類,每個對應一個消息類型:
class Person(message.Message):
class AddressBook(message.Message):
這裏每個類最重要的一行是 __metaclass__=reflection.GeneratedProtocolMessage
最後就是你可以使用 Person 類來操作相關字段了。例如你可以寫:
import addressbook_pb2
person=addressbook_pb2.Person()
person.id=1234
person.name="John Doe"
person.email="[email protected]"
phone=person.phone.add()
phone.number="555-4321"
phone.type=addressbook_pb2.Person.HOME
需要注意的是這些賦值屬性並不是簡單的增加新字段到Python對象,如果你嘗試給一個 .proto 文件中沒有定義的字段賦值,就會拋出 AttributeError 異常,如果賦值類型錯誤會拋出 TypeError。在給一個字段賦值之前讀取會返回缺省值:
person.no_such_field=1
person.id="1234"
更多相關信息參考( http://code.google.com/apis/protocolbuffers/docs/reference/python-generated.html )。
7.5.1
枚舉在元類中定義爲一些符號常量對應的數字。例如常量 addressbook_pb2.Person.WORK 擁有值2。
7.5.2
每個消息類包含一些其他方法允許你檢查和控制整個消息,包括:
·
·
·
·
這些方法是通過接口 Message 實現的,更多消息參考( http://code.google.com/apis/protocolbuffers/docs/reference/python/google.protobuf.message.Message-class.html )。
7.5.3
最後,每個ProtocolBuffer類有些方法用於讀寫消息的二進制數據( http://code.google.com/apis/protocolbuffers/docs/encoding.html )。包括:
·
·
他們是成對使用的,提供二進制數據的串行化和解析。另外參考消息API參考( http://code.google.com/apis/protocolbuffers/docs/reference/python/google.protobuf.message.Message-class.html )瞭解更多信息。
Note
ProtocolBuffer與面向對象設計
ProtocolBuffer類只是用於存取數據的,類似於C++中的結構體,他們並沒有在面向對象方面做很好的設計。如果你想要給這些類添加更多的行爲,最好的方法是包裝(wrap)。包裝同樣適合於複用別人寫好的 .proto 文件。這種情況下,你可以把ProtocolBuffer生成類包裝的很適合於你的應用,並隱藏一些數據和方法,暴露有用的函數等等。 你不可以通過繼承來給自動生成的類添加行爲。 這會破壞他們的內部工作機制。
7.6
現在開始嘗試使用ProtocolBuffer的類。第一件事是讓地址本應用可以記錄聯繫人的細節信息。想要做這些需要先創建聯繫人實例,然後寫入到輸出流。
這裏的程序從文件讀取地址本,添加新的聯繫人信息,然後寫回新的地址本到文件。
#! /usr/bin/python
import addressbook_pb2
import sys
#這個函數使用用戶輸入填充聯繫人信息
def PromptForAddress(person):
#主函數,從文件讀取地址本,添加新的聯繫人,然後寫回到文件
if len(sys.argv)!=2:
address_book=addressbook_pb2.AddressBook()
#讀取已經存在的地址本
try:
except OSError:
#添加地址
PromptFromAddress(address_book.person.add())
#寫入到文件
f=open(sys.argv[1],"wb")
f.write(address_book.SerializeToString())
f.close()
7.7
當然,一個無法讀取的地址本是沒什麼用處的,這個例子讀取剛纔創建的文件並打印所有信息:
#! /usr/bin/python
import addressbook_pb2
import sys
#遍歷地址本中所有的人並打印出來
def ListPeople(address_book):
#主函數,從文件讀取地址本
if len(sys.argv)!=2:
address_book=addressbook_pb2.AddressBook()
#讀取整個地址本文件
f=open(sys.argv[1],"rb")
address_book.ParseFromString(f.read())
f.close()
ListPeople(address_book)
7.8
在你發不了代碼以後,可能會想要改進ProtocolBuffer的定義。如果你想新的數據結構向後兼容,而你的舊數據可以向前兼容,那麼你就找對了東西了,不過有些規則需要遵守。在新版本的ProtocolBuffer中:
·
·
·
·
這些規則也有例外( http://code.google.com/apis/protocolbuffers/docs/proto.html#updating ),不過很少使用。
如果你遵從這些規則,舊代碼會很容易的讀取新的消息,並簡單的忽略新的字段。而對舊的被刪除的可選字段也會簡單的使用他們的缺省值,被刪除的重複字段會自動爲空。新的代碼也會透明的讀取舊的消息。然而,需要注意的是新的可選消息不會在舊的消息中顯示,所以你需要使用 has_ 嚴格的檢查他們是否存在,或者在 .proto 文件中提供一個缺省值。如果沒有缺省值,就會有一個類型相關的默認缺省值:對於字符串就是空字符串;對於布爾型則是false;對於數字類型默認爲0。同時要注意的是如果你添加了新的重複字段,你的新代碼不會告訴你這個字段爲空(新代碼)也不會,也不會(舊代碼)包含 has_ 標誌。
7.9
ProtocolBuffer不僅僅提供了數據結構的存取和串行化。查看Python API參考( http://code.google.com/apis/protocolbuffers/docs/reference/python/index.html )瞭解更多功能。
一個核心功能是通過消息類的映射(reflection)提供的。你可以通過它遍歷消息的所有字段,和管理他們的值。關於映射的一個很有用的地方是轉換到其他編碼,如XML或JSON。一個使用映射的更高級的功能是尋找同類型兩個消息的差異,或者開發出排序、正則表達式等功能。使用你的創造力,還可以用ProtocolBuffer實現比你以前想象的更多的問題。
映射是通過消息接口提供的。
本頁提供了Python生成類的相關細節。你可以在閱讀本文檔之前查看語言指導。
Python的ProtocolBuffer實現與C++和Java的略有不同,編譯器只輸出構建代碼的描述符來生成類,而由Python的元類來執行工作。本文檔描述了元類開始生效以後的東西。
13.1
ProtocolBuffer通過編譯器的 –python_out= 選項來生成Python的相關類。這個參數實際上是指定輸出的Python類放在哪個目錄下。編譯器會爲每個 .proto 文件生成一個對應的 .py 文件。輸出文件名與輸入文件名相關,不過有兩處修改:
·
·
如果你按照如下調用編譯器:
protoc --proto_path=src --python_out=build/gen src/foo.proto src/bar/baz.proto
編譯器會自動讀取兩個 .proto 文件然後產生兩個輸出文件。在需要時編譯器會自動創建目錄,不過 –python_out 指定的目錄不會自動創建。
需要注意的是,如果 .proto 文件名或路徑包含有無法在Python中使用的模塊名(如連字符),就會被自動轉換爲下劃線。所以文件 foo-bar.proto 會變成 foo_bar_pb2.py 。
Note
在每個文件後綴的 _pb2.py 中的2代表ProtocolBuffer版本2。版本1僅在Google內部使用,但是你仍然可以在以前發佈的一些代碼中找到它。自動版本2開始,ProtocolBuffer開始使用完全不同的接口了,從此Python也沒有編譯時類型檢查了,我們加上這個版本號來標誌Python文件名。
13.2
Python代碼生成根本不在乎包的名字。因爲Python使用目錄名來做包名。
13.3
先看看一個簡單的消息聲明:
message Foo {}
ProtocolBuffer編譯器會生成類Foo,它是 google.protobuf.Message 的子類。這個實體類,不含有虛擬方法。不像C++和Java,Python生成類對優化選項不感冒;實際上Python的生成代碼已經爲代碼大小做了優化。
你不能繼承Foo的子類。生成類被設計不可以被繼承,否則會被打破一些設計。另外,繼承本類也是不好的設計。
Python的消息類沒有特定的公共成員,而是定義接口,極其嵌套的字段、消息和枚舉類型。
一個消息可以在另外一個消息中聲明,例如 message Foo { message Bar {}} 。在這種情況下,Bar類定義爲Foo的一個靜態成員,所以你可以通過 Foo.Bar 來引用。
13.4
對於消息類型中的每一個字段,都有對應的同名成員。
13.4.1
如果你有一個簡單字段(包括可選的和重複的),也就是非消息字段,你可以通過簡單字段的方式來管理,例如foo字段的類型是int32,你可以:
message.foo=123
print message.foo
注意設置foo的值,如果類型錯誤會拋出TypeError。
如果foo在賦值之前就讀取,就會使用缺省值。想要檢查是否已經賦值,可以用 HasField() ,而清除該字段的值用 ClearField() 。例如:
assert not message.HasField("foo")
message.foo=123
assert message.HasField("foo")
message.ClearField("foo")
assert not message.HasField("foo")
13.4.2
消息類型工作方式略有不同。你無法爲一個嵌入消息字段賦值。而是直接操作這個消息的成員。因爲實例化上層消息時,其包含的子消息同時也實例化了,例如定義:
message Foo {
}
message bar {
}
你不可以這麼做,因爲不能做消息類型字段的賦值:
foo=Foo()
foo.bar=Bar()
而是可以直接對消息類型字段的成員賦值:
foo=Foo()
assert not foo.HasField("bar")
foo.bar.i=1
assert foo.HasField("bar")
注意簡單的讀取消息類型字段的未賦值成員只不過是打印其缺省值:
foo=Foo()
assert not foo.HasField("bar")
print foo.bar.i #打印i的缺省值
assert not foo.HasField("bar")
13.4.3
重複字段表現的像是Python的序列類型。如果是嵌入的消息,你無法爲字段直接賦值,但是你可以管理。例如給定的定義:
message Foo {
}
你就可以這麼做:
foo=Foo()
foo.nums.append(15)
foo.nums.append(32)
assert len(foo.nums)==2
assert foo.nums[0]==15
assert foo.nums[1]==32
for i in foo.nums:
foo.nums[1]=56
assert foo.nums[1]==56
作爲一種簡單字段,清除該字段必須使用 ClearField() 。
13.4.4
重複消息字段工作方式與重複字段很像,除了 add() 方法用於返回新的對象以外。例如如下定義:
message Foo {
}
message Bar {
}
你可以這麼做:
foo=Foo()
bar=foo.bars.add()
bar.i=15
bar=foo.bars.add()
bar.i=32
assert len(foo.bars)==2
assert foo.bars[0].i==15
assert foo.bars[1].i==32
for bar in foo.bars:
foo.bars[1].i=56
assert foo.bars[1].i==56
13.5.1
一個簡單的接口定義:
service Foo {
}
ProtocolBuffer的編譯器會生成類 Foo 來展示這個服務。 Foo 將會擁有每個服務定義的方法。在這種情況下 Bar 方法的定義是:
def Bar(self,rpc_controller,request,done)
參數等效於 Service.CallMethod() ,除了隱含的 method_descriptor 參數。
這些生成的方法被定義爲可以被子類重載。缺省實現只是簡單的調用 controller.SetFailed() 而拋出錯誤信息告之尚未實現。然後調用done回調。在實現你自己的服務時,你必須繼承生成類,然後重載各個接口方法。
Foo繼承了 Service 接口。ProtocolBuffer編譯器會自動聲響相關的實現方法:
·
·
·
13.5.2
ProtocolBuffer編譯器也會爲每個服務接口提供一個存根實現,用於客戶端發送請求到服務器。對於Foo服務,存根實現是 Foo_Stub 。
Foo_Stub 是Foo的子類,他的構造器是一個 RpcChannel 。存根會實現調用每個服務方法的CallMethod() 。
ProtocolBuffer哭並不包含RPC實現。然而,它包含了你構造服務類的所有工具,不過選擇RPC實現則隨你喜歡。你只需要提供 RpcChannel 和 RpcController 的實現即可。
http://www.cppblog.com/liquidx