.Net環境下調用ProtoBuf


一、什么是ProtoBuf

protocolbuffer(以下簡稱PB)是google 的一種數據交換的格式,它獨立於語言,獨立於平台。它是一種類似於xml、json等類似作用的交互格式。由於它是一種二進制的格式,比使用 xml 進行數據交換快許多。

google 提供了多種語言的實現:java、c#、c++、go 和 python,每一種實現都包含了相應語言的編譯器以及庫文件。可以把它用於分布式應用之間的數據通信或者異構環境下的數據交換。

作為一種效率和兼容性都很優秀的二進制數據傳輸格式,可以用於諸如網絡傳輸、配置文件、數據存儲等諸多領域。

隨着移動市場的異軍突起以及它自身的優點,PB最為一種數據交換格式徹底火了。

二、ProtoBuf的版本

PB具有三個版本:

  一、Google官方版本:https://github.com/google/protobuf/tree/master/csharp(谷歌官方開發、比較晦澀,主庫名字:Google.ProtoBuf.dll)

  二、.Net社區版本:https://github.com/mgravell/protobuf-net(.Net社區愛好者開發,寫法上比較符合.net上的語法習慣,主庫名字:protobuf-net.dll)

  三、.Net社區版本(二):https://github.com/jskeet/protobuf-csharp-port(據說是由谷歌的.net員工為.net開發,在官方沒有出來csharp的時候開發,到發博文時還在維護,主庫名字:Google.ProtocolBuffers.dll)

至於選用那個版本,跨平台的需求不大的話,可以用版本二、大的話可以選用一或者三。(本文后續選用二為例)

三、ProtoBuf有什么用

  (1)制作網絡通信協議。

  (2)數據的存儲(序列化和反序列化),類似於xml、json等;

 我們先來看(1)。PB可以利用一種語言(作者簡稱pb語言源碼,文件后綴為.proto)轉化為通信類(.cs文件,其他語言會生成相應的后綴文件,如.h,.cpp的)。在此過程中需要用protoc.exe命令行工具生成.bin,然后用

ProtoGen.exe生成.cs文件,至於怎么調用命令行,這里不再贅述。倒是可以把這三個文件(有的可能需要ProtoGen.exe.config)放到一個目錄下,然后寫一個命令行文件.bat直接生成。

echo on

set Path=ProtoGen\protogen.exe

%Path%  -i:Message.proto    -o:OpenAPIModel\Message.cs

pause

注意:不同的版本命令行是不一樣的。(如果嫌麻煩,可以自己手擼協議,本人就是這么干的,不過注意各修飾字段,不過手擼只適用於版本二,因為其他的寫法生不一樣,生成.cs文件的時候需要同時生成一些方法)

我的一個proto文件

message Message
{
    required  string messageType=1;//消息類型,約定link為建立連接消息,command為命令消息,file為文件,fileToClient為到客戶端的文件
    optional string sourceIp=2;
    optional string sourcePort=3;
    optional string content=4;    //消息內容
    optional stirng fileName=5;
    optional bytes bytes = 9999;//文件數組
    optional string other = 6;//預留
    optional int32 fileTotalLength = 7;//文件總長度
    optional int32 fileIndex = 8;      //當前傳輸的下標
    optional int32 fileTotalCount = 9; //文件拆分總個數

}

我自己手擼的文件

using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

namespace AndroidSocketTest
{
    [ProtoContract]
    public class Message
    {
        [ProtoMember(1)]
        public string messageType { get; set; }
        [ProtoMember(2)]
        public string sourceIp { get; set; }
        [ProtoMember(3)]
        public string sourcePort { get; set; }
        [ProtoMember(4)]
        public string content { get; set; }    //消息內容
        [ProtoMember(5)]
        public string fileName { get; set; }
        private byte[] _bytes = null;
        [global::ProtoBuf.ProtoMember(9999, IsRequired = false, Name = @"bytes", DataFormat = global::ProtoBuf.DataFormat.Default)]
        [global::System.ComponentModel.DefaultValue(null)]
        public byte[] bytes
        {
            get { return _bytes; }
            set { _bytes = value; }
        }
        [ProtoMember(6)]
        public string other { get; set; }    //預留
        [ProtoMember(7)]
        public int fileTotalLength { get; set; } //文件總長度
        [ProtoMember(8)]
        public int fileIndex { get; set; }       //文件當前段數
        [ProtoMember(9)]
        public int fileTotalCount{get;set; }   //文件總片數 
    }

    public static class MessageHelp
    {
        // 將消息序列化為二進制的方法  
        // < param name="model">要序列化的對象< /param>  
        public static byte[] Serialize(Message model)
        {
            try
            {
                //涉及格式轉換,需要用到流,將二進制序列化到流中  
                using (MemoryStream ms = new MemoryStream())
                {
                    //使用ProtoBuf工具的序列化方法  
                    ProtoBuf.Serializer.Serialize<Message>(ms, model);
                    //定義二級制數組,保存序列化后的結果  
                    byte[] result = new byte[ms.Length];
                    //將流的位置設為0,起始點  
                    ms.Position = 0;
                    //將流中的內容讀取到二進制數組中  
                    ms.Read(result, 0, result.Length);
                    return result;
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        // 將收到的消息反序列化成對象  
        // < returns>The serialize.< /returns>  
        // < param name="msg">收到的消息.</param>  
        public static Message DeSerialize(byte[] msg)
        {
            try
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    //將消息寫入流中  
                    ms.Write(msg, 0, msg.Length);
                    //將流的位置歸0  
                    ms.Position = 0;
                    //使用工具反序列化對象  
                    Message result = ProtoBuf.Serializer.Deserialize<Message>(ms);
                    return result;
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }
    }
}

連下面的序列化和反序列化都寫好了。

四、proto語法,引用一個同行的博客

http://blog.csdn.net/u014308482/article/details/52958148

 

有問題請加群溝通qq:568055323


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM