初用protobuf-csharp-port

下面這個用法是參照protobuf-csharp-port的官方wiki,參見:服務器

https://code.google.com/p/protobuf-csharp-port/wiki/GettingStarted架構

官方原文裏的用法與代碼已經有些不匹配了,須要作一些小的修改。併發

準備工做

1.首先從https://code.google.com/p/protobuf-csharp-port這個上面把源代碼下載下來,我這個版本是protobuf-csharp-port-2.4.1.521-source(r523)app

2.下載後是個壓縮包,解壓目錄,以下圖:函數

點開「Build」文件夾:工具

看見那個BuildAll.bat,點擊它會自動執行編譯操做,編譯完成後將出現build_output和build_temp兩個輸出文件夾,其中build_output以下圖所示例:優化

生成的Google.ProtocolBuffers.dll將被用做外部連接的DLL使用,這裏有個問題,能不能不用作DLL使用呢?由於衆所周知的AOT,JIT問題。ui

例子: an address book

這塊將會用一個程序來演示如何使用這個protocBufferthis

The .proto file

看看下面這個proto文件,分析下這個文件都描述了什麼信息。此文件在 你下載的源代碼文件夾的protos/tutorial。google

package tutorial;
 
import "google/protobuf/csharp_options.proto";

option (google.protobuf.csharp_file_options).namespace = "Google.ProtocolBuffers.Examples.AddressBook";
option (google.protobuf.csharp_file_options).umbrella_classname = "AddressBookProtos";

option optimize_for = SPEED;

message Person {
  required string name = 1;
  required int32 id = 2;        // Unique ID number for this person.
  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;
}
 
// Our address book file is just one of these.
message AddressBook {
  repeated Person person = 1;
}

這個文件和谷歌官方提供的基本一致,但作了一些調整:

  • 爲了簡單期間去掉了輸出Java代碼的選項。這裏若是須要就把Java選項加上便可,和C#沒有衝突。
  • 導入項代碼: google/protobuf/csharp_options.proto ,目的是使用C#擴展。
  • 指定了兩項C#特有的選項:
    • The name of the class containing the descriptor representing the overall .proto file. (This is called the "umbrella" class.) The generated source file is also named after this class. In this case we're using AddressBookProtos.
    • 生成類的命名空間。這裏用的是: Google.ProtocolBuffers.Examples.AddressBook.
  • 指定了一個優化的選項。會多生成一些代碼,但能提升運行效率。
  • 還有其餘的選項,能夠看看code.google上的description裏的說明。

 

生成源代碼

轉到你的源代碼目錄,執行如下操做

protogen ..\..\protos\tutorial\addressbook.proto 
         ..\..\protos\google\protobuf\csharp_options.proto 
         ..\..\protos\google\protobuf\descriptor.proto
         --proto_path=..\..\protos

看看build_temp文件夾,以下圖所示:

在GeneratedSource文件夾中,就能找到AddressBookProtos.cs文件了:

這個AddressBookProtos.cs文件是咱們後邊須要用到的,其餘文件只是Google用到的,咱們不用去管,或者能把這些代碼做爲源代碼引入主工程?不得而知。

注意事項:

  1. Make sure that you do not use a non-ASCII encoding with your text file. The protoc.exe compiler will complain with the following message:
    tutorial/addressbook.proto:1:1: Expected top-level statement (e.g. "message").

    The best way to fix this is with Visual Studio. Open the proto file and select "File" -> "Save as...". From the save dialog click the down arrow next to     the save button and select "Save with Encoding". Select the "US-ASCII" codepage (near the bottom) and click save.

  2. It's often easiest keep all your proto files in a single directory tree. This allows to omit the --proto_path option by running protoc.exe from the top of     the this directory tree. Always keep the 'google/protobuf/*.proto' files available so that you can import them to specify options, or use the options     through protogen.

  3.Unlike a programming language like C# it is usually expected that your proto file will specify numerous messages, not one. Name your proto files     based on the namespace, not the message. Create proto files only as often as you would create a new namespace to organize those classes.

使用生成的源代碼

爲了使用上面生成的cs文件,咱們須要執行下面這些操做:

  1. 建立一個builder,後邊將用它來構造Person這個消息體
  2. 設置builder的屬性
  3. 使用這個builder來建立 Person 消息體
  4. 將 Person 寫入內存流
  5. 使用上面寫好數據的內存流,再建立一個新的Person消息體
  6. 建立一個AddressBook的builder ,而後把這個剛建立的Person消息體賦值給它
  7. 使用AddressBook的builder 和上面的數據流建立 AddressBook

將這個AddressBook裏的Person和第三步建立的Person進行比較,看數據是否一致。

    static void Sample()
    {
        byte[] bytes;
        //Create a builder to start building a message
        Person.Builder newContact = Person.CreateBuilder();
        //Set the primitive properties
        newContact.SetId(1)
                  .SetName("Foo")
                  .SetEmail("foo@bar");
        //Now add an item to a list (repeating) field
        newContact.AddPhone(
            //Create the child message inline
            Person.Types.PhoneNumber.CreateBuilder().SetNumber("555-1212").Build()
            );
        //Now build the final message:
        Person person = newContact.Build();
        //The builder is no longer valid (at least not now, scheduled for 2.4):
        newContact = null;
        using(MemoryStream stream = new MemoryStream())
        {
            //Save the person to a stream
            person.WriteTo(stream);
            bytes = stream.ToArray();
        }
        //Create another builder, merge the byte[], and build the message:
        Person copy = Person.CreateBuilder().MergeFrom(bytes).Build();

        //A more streamlined approach might look like this:
        bytes = AddressBook.CreateBuilder().AddPerson(copy).Build().ToByteArray();
        //And read the address book back again
        AddressBook restored = AddressBook.CreateBuilder().MergeFrom(bytes).Build();
        //The message performs a deep-comparison on equality:
        if(restored.PersonCount != 1 || !person.Equals(restored.PersonList[0]))
            throw new ApplicationException("There is a bad person in here!");
    }

   用VS2013,建立一個WinForm程序,拖一個button上去,雙擊出事件,調用Sample函數便可,這樣就通了。裏面還有不少細節沒說清楚,不過好歹有整塊的東西了。那麼後邊的工做,須要分紅幾步來執行:

1.將上述流程分析清楚,有一個初步的架構圖和UML圖。

2.C#客戶端的二進制內存流,顯示須要鋪設一個二進制的內存流管理器,是否須要參考以前的那個二進制管理器呢。

3.如何集成到Unity裏,首先要寫一份關於Unity的代碼規範和內存處理規範。若是集成到Unity裏,那麼勢必兩頭都要寫代碼,加油啊。

4.如何搭建一個Java服務器,支持解析數據,併發送和接收。

5.鏈接Java服務器通訊。客戶端和服務器兩頭看看可否順利工做。

相關文章
相關標籤/搜索