ProtoBuf.net 的简单使用
一、什么是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语法,引用一个同行的博客