1. 程式人生 > >gRPC-Protocol基礎知識-C#篇

gRPC-Protocol基礎知識-C#篇

本文使用協議緩衝區語言的[proto3](https://developers.google.com/protocol-buffers/docs/proto3)版本,為C#程式設計師提供了使用協議緩衝區的基本介紹。 通過建立一個簡單的示例應用程式,展示瞭如何 * 在.proto檔案中定義訊息格式。 * 使用協議緩衝區編譯器。 * 使用C#協議緩衝區API寫入和讀取訊息。 []() 這不是在C#中使用協議緩衝區的全面指南。 有關更多詳細的參考資訊,請參閱《[協議緩衝區語言指南](https://developers.google.com/protocol-buffers/docs/proto3)》,《 [C#API參考](https://developers.google.com/protocol-buffers/docs/reference/csharp)》,《 [C#生成的程式碼指南](https://developers.google.com/protocol-buffers/docs/reference/csharp-generated)》和《[編碼參考](https://developers.google.com/protocol-buffers/docs/encoding)》。 ###為什麼要使用協議緩衝區? 我們將使用的示例是一個非常簡單的“地址簿”應用程式,該應用程式可以在檔案中讀寫人的聯絡方式。通訊錄中的每個人都有一個姓名,一個ID,一個電子郵件地址和一個聯絡電話。 您如何像這樣序列化和檢索結構化資料?有幾種方法可以解決此問題: 將.NET二進位制序列化與System.Runtime.Serialization.Formatters.Binary.BinaryFormatter和關聯的類一起使用。面對變化,這最終變得非常脆弱,在某些情況下,資料大小非常昂貴。如果您需要與為其他平臺編寫的應用程式共享資料,它也不是很好。 您可以發明一種將資料項編碼為單個字串的臨時方法,例如將4個整數編碼為“ 12:3:-23:67”。儘管確實需要編寫一次性的編碼和解析程式碼,但是這是一種簡單且靈活的方法,而且解析帶來的執行時成本很小。這對於編碼非常簡單的資料最有效。 將資料序列化為XML。由於XML是人類(一種)可讀的,並且存在用於多種語言的繫結庫,因此這種方法可能非常有吸引力。如果要與其他應用程式/專案共享資料,這可能是一個不錯的選擇。但是,眾所周知,XML佔用大量空間,對它進行編碼/解碼會給應用程式帶來巨大的效能損失。同樣,導航XML DOM樹比通常導航類中的簡單欄位要複雜得多。 協議緩衝區是靈活,高效,自動化的解決方案,可以準確地解決此問題。使用協議緩衝區,您可以編寫要儲存的資料結構的.proto描述。由此,協議緩衝區編譯器建立了一個類,該類以有效的二進位制格式實現協議緩衝區資料的自動編碼和解析。生成的類為構成協議緩衝區的欄位提供獲取器和設定器,並以協議為單位來處理讀寫協議緩衝區的詳細資訊。重要的是,協議緩衝區格式支援隨時間擴充套件格式的想法,以使程式碼仍可以讀取以舊格式編碼的資料。 ###在哪裡找到示例程式碼? 我們的示例是一個命令列應用程式,用於管理使用協議緩衝區編碼的地址簿資料檔案。 命令AddressBook(請參閱:[Program.cs](https://github.com/protocolbuffers/protobuf/blob/master/csharp/src/AddressBook/Program.cs))可以將新條目新增到資料檔案或解析資料檔案並將資料列印到控制檯。 您可以在GitHub儲存庫的[examples目錄](https://github.com/protocolbuffers/protobuf/tree/master/examples)和[csharp / src / AddressBook目錄](https://github.com/protocolbuffers/protobuf/tree/master/csharp/src/AddressBook)中找到完整的示例。 ###定義協議格式 要建立地址簿應用程式,您需要以.proto檔案開頭。 .proto檔案中的定義很簡單:您為要序列化的每個資料結構新增一條訊息,然後為訊息中的每個欄位指定名稱和型別。 在我們的示例中,定義訊息的.proto檔案是[addressbook.proto](https://github.com/protocolbuffers/protobuf/blob/master/examples/addressbook.proto)。 .proto檔案以程式包宣告開頭,這有助於防止不同專案之間的命名衝突。 ``` syntax = "proto3"; package tutorial; import "google/protobuf/timestamp.proto"; ``` 在C#中,如果未指定csharp_namespace,則將生成的類放置在與程式包名稱匹配的名稱空間中。 在我們的示例中,指定了csharp_namespace選項以覆蓋預設值,因此生成的程式碼使用Google.Protobuf.Examples.AddressBook的名稱空間而不是Tutorial。 ``` option csharp_namespace = "Google.Protobuf.Examples.AddressBook"; ``` 接下來,您將擁有訊息定義。 訊息只是包含一組型別欄位的彙總。 許多標準的簡單資料型別可用作欄位型別,包括bool,int32,float,double和string。 您還可以通過使用其他訊息型別作為欄位型別來為訊息新增更多的結構。 ``` message Person { string name = 1; int32 id = 2; // Unique ID number for this person. string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { string number = 1; PhoneType type = 2; } repeated PhoneNumber phones = 4; google.protobuf.Timestamp last_updated = 5; } // Our address book file is just one of these. message AddressBook { repeated Person people = 1; } ``` 在上面的示例中,Person訊息包含PhoneNumber訊息,而AddressBook訊息包含Person訊息。您甚至可以定義巢狀在其他訊息中的訊息型別-如您所見,PhoneNumber型別在Person內部定義。如果希望您的欄位之一具有預定義的值列表之一,也可以定義列舉型別-在這裡您要指定電話號碼可以是MOBILE,HOME或WORK之一。 每個元素上的“ = 1”,“ = 2”標記標識該欄位在二進位制編碼中使用的唯一“標記”。標籤編號1至15與較高的編號相比,編碼所需的位元組減少了一個位元組,因此,為了進行優化,您可以決定將這些標籤用於常用或重複的元素,而將標籤16和更高的標籤用於較少使用的可選元素。重複欄位中的每個元素都需要重新編碼標籤號,因此重複欄位是此優化的最佳候選者。 如果未設定欄位值,則使用[預設值](https://developers.google.com/protocol-buffers/docs/proto3#default):數字型別為零,字串為空字串,布林值為false。對於嵌入式訊息,預設值始終是訊息的“預設例項”或“原型”,沒有設定任何欄位。呼叫訪問器以獲取尚未顯式設定的欄位的值將始終返回該欄位的預設值。 如果重複一個欄位,則該欄位可以重複任意次(包括零次)。重複值的順序將保留在協議緩衝區中。將重複欄位視為動態大小的陣列。 在[協議緩衝區語言指南](https://developers.google.com/protocol-buffers/docs/proto3)中,您將找到有關編寫.proto檔案的完整指南-包括所有可能的欄位型別。但是,不要去尋找類似於類繼承的工具–協議緩衝區不能做到這一點。 ###編譯協議緩衝區 現在,您有了.proto,接下來需要做的是生成讀取和寫入AddressBook(以及Person和PhoneNumber)訊息所需的類。 為此,您需要在.proto上執行協議緩衝區編譯器協議: * 如果尚未安裝編譯器,請[下載軟體包](https://developers.google.com/protocol-buffers/docs/downloads)並按照自述檔案中的說明進行操作。 * 現在執行編譯器,指定源目錄(應用程式的原始碼所在的位置;如果您不提供值,則使用當前目錄),目標目錄(您希望生成的程式碼進入的位置;通常與$相同) SRC_DIR),以及.proto的路徑。 在這種情況下,您將呼叫: ``` protoc -I=$SRC_DIR --csharp_out=$DST_DIR $SRC_DIR/addressbook.proto ``` 因為需要C#程式碼,所以使用--csharp_out選項–其他受支援的語言也提供了類似的選項。 這將在您指定的目標目錄中生成Addressbook.cs。 要編譯此程式碼,您需要一個引用[Google.Protobuf](https://www.nuget.org/packages/Google.Protobuf)程式集的專案。 ###通訊錄類 生成Addressbook.cs提供了五種有用的型別: * 靜態地址簿類,其中包含有關協議緩衝區訊息的元資料。 * 具有隻讀People屬性的AddressBook類。 * 具有“名稱”,“ ID”,“電子郵件”和“電話”屬性的Person類。 * 一個PhoneNumber類,巢狀在靜態Person.Types類中。 * 一個PhoneType列舉,也巢狀在Person.Types中。 您可以在《[ C#生成的程式碼](https://developers.google.com/protocol-buffers/docs/reference/csharp-generated)》指南中詳細瞭解確切生成的內容的詳細資訊,但是在大多數情況下,您可以將它們視為完全普通的C#型別。需要強調的一點是,對應於重複欄位的任何屬性都是隻讀的。您可以向集合中新增專案或從集合中刪除專案,但是不能用完全獨立的集合來替換它。重複欄位的收集型別始終為Repeat