对于Socket应用来说,如何序列化和反序列化消息一直是比较头痛的问题,C#提供了自动序列化的功能(类似AS3中的AMF),但是唯一的缺点就是前后端都必须是C#实现,如果前后端语言不一致该怎么办?

Google的Protobuf很好的解决了这个问题,支持类似C++、Java等主流语言,但是官方版本未提供C#语言的实现,但是不用担心,有很多开发者已经帮助我们实现了C#的Protobuf,其中应用得最多的是Protobuf-net,下载地址是:http://code.google.com/p/protobuf-net/

当然如果404了也不用担心,我提供了一个百度网盘的下载:http://pan.baidu.com/s/1o6qTFEa

解压后即可使用,下面我们创建两个协议示例文件来展示一下Protobuf的用法,其中一个文件用到了另一个文件定义的消息体:

test1.proto:

 //这里定义基础的消息体或枚举

 package Test.Base;

 //定义枚举

 enum Sex
{
MALE = ;
FEMALE = ;
} //定义消息体 message People
{
required string name = ;
required Sex sex = ;
optional int32 age = ;
} message Hero
{
required People people = ;
optional string skill = ;
}

test2.proto:

 //有用到 test1 的东西需要导入 test1

 import "test1.proto";

 //这里定义直接使用的消息体

 package Test.App;

 //定义消息体

 message SuperHero
{
required Test.Base.Hero hero = ;
required string superSkill = ;
}

那么该如何生成可以使用的代码呢?

一般通过命令行进行生成,但是如果每次修改了协议都敲一通肯定会累死人的,下面在test1.proto和test2.proto的同一目录下新建一个名为gen.cmd的文件,内容如下:

 D:\project\tool\protobuf-net\ProtoGen\protogen.exe -i:test1.proto -i:test2.proto -o:test.cs
pause

当前protogen.exe的路径以你自己的为准,双击会在本目录下生成test.cs文件。

生成的test.cs内容如下:

 //------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------ // Generated from: test1.proto
namespace Test.Base
{
[global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"People")]
public partial class People : global::ProtoBuf.IExtensible
{
public People() {} private string _name;
[global::ProtoBuf.ProtoMember(, IsRequired = true, Name=@"name", DataFormat = global::ProtoBuf.DataFormat.Default)]
public string name
{
get { return _name; }
set { _name = value; }
}
private Test.Base.Sex _sex;
[global::ProtoBuf.ProtoMember(, IsRequired = true, Name=@"sex", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
public Test.Base.Sex sex
{
get { return _sex; }
set { _sex = value; }
}
private int _age = default(int);
[global::ProtoBuf.ProtoMember(, IsRequired = false, Name=@"age", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
[global::System.ComponentModel.DefaultValue(default(int))]
public int age
{
get { return _age; }
set { _age = value; }
}
private global::ProtoBuf.IExtension extensionObject;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
{ return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
} [global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"Hero")]
public partial class Hero : global::ProtoBuf.IExtensible
{
public Hero() {} private Test.Base.People _people;
[global::ProtoBuf.ProtoMember(, IsRequired = true, Name=@"people", DataFormat = global::ProtoBuf.DataFormat.Default)]
public Test.Base.People people
{
get { return _people; }
set { _people = value; }
}
private string _skill = "";
[global::ProtoBuf.ProtoMember(, IsRequired = false, Name=@"skill", DataFormat = global::ProtoBuf.DataFormat.Default)]
[global::System.ComponentModel.DefaultValue("")]
public string skill
{
get { return _skill; }
set { _skill = value; }
}
private global::ProtoBuf.IExtension extensionObject;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
{ return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
} [global::ProtoBuf.ProtoContract(Name=@"Sex")]
public enum Sex
{ [global::ProtoBuf.ProtoEnum(Name=@"MALE", Value=)]
MALE = , [global::ProtoBuf.ProtoEnum(Name=@"FEMALE", Value=)]
FEMALE =
} }
// Generated from: test2.proto
// Note: requires additional types generated from: test1.proto
namespace Test.App
{
[global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"SuperHero")]
public partial class SuperHero : global::ProtoBuf.IExtensible
{
public SuperHero() {} private Test.Base.Hero _hero;
[global::ProtoBuf.ProtoMember(, IsRequired = true, Name=@"hero", DataFormat = global::ProtoBuf.DataFormat.Default)]
public Test.Base.Hero hero
{
get { return _hero; }
set { _hero = value; }
}
private string _superSkill;
[global::ProtoBuf.ProtoMember(, IsRequired = true, Name=@"superSkill", DataFormat = global::ProtoBuf.DataFormat.Default)]
public string superSkill
{
get { return _superSkill; }
set { _superSkill = value; }
}
private global::ProtoBuf.IExtension extensionObject;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
{ return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
} }

当前如果要生成两个文件而非一个时可以这么写:

 D:\project\tool\protobuf-net\ProtoGen\protogen.exe -i:test1.proto -o:test1.cs
D:\project\tool\protobuf-net\ProtoGen\protogen.exe -i:test2.proto -o:test2.cs
pause

生成的test1.cs:

 //------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------ // Generated from: test1.proto
namespace Test.Base
{
[global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"People")]
public partial class People : global::ProtoBuf.IExtensible
{
public People() {} private string _name;
[global::ProtoBuf.ProtoMember(, IsRequired = true, Name=@"name", DataFormat = global::ProtoBuf.DataFormat.Default)]
public string name
{
get { return _name; }
set { _name = value; }
}
private Test.Base.Sex _sex;
[global::ProtoBuf.ProtoMember(, IsRequired = true, Name=@"sex", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
public Test.Base.Sex sex
{
get { return _sex; }
set { _sex = value; }
}
private int _age = default(int);
[global::ProtoBuf.ProtoMember(, IsRequired = false, Name=@"age", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
[global::System.ComponentModel.DefaultValue(default(int))]
public int age
{
get { return _age; }
set { _age = value; }
}
private global::ProtoBuf.IExtension extensionObject;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
{ return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
} [global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"Hero")]
public partial class Hero : global::ProtoBuf.IExtensible
{
public Hero() {} private Test.Base.People _people;
[global::ProtoBuf.ProtoMember(, IsRequired = true, Name=@"people", DataFormat = global::ProtoBuf.DataFormat.Default)]
public Test.Base.People people
{
get { return _people; }
set { _people = value; }
}
private string _skill = "";
[global::ProtoBuf.ProtoMember(, IsRequired = false, Name=@"skill", DataFormat = global::ProtoBuf.DataFormat.Default)]
[global::System.ComponentModel.DefaultValue("")]
public string skill
{
get { return _skill; }
set { _skill = value; }
}
private global::ProtoBuf.IExtension extensionObject;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
{ return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
} [global::ProtoBuf.ProtoContract(Name=@"Sex")]
public enum Sex
{ [global::ProtoBuf.ProtoEnum(Name=@"MALE", Value=)]
MALE = , [global::ProtoBuf.ProtoEnum(Name=@"FEMALE", Value=)]
FEMALE =
} }

生成的test2.cs:

 //------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------ // Generated from: test2.proto
// Note: requires additional types generated from: test1.proto
namespace Test.App
{
[global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"SuperHero")]
public partial class SuperHero : global::ProtoBuf.IExtensible
{
public SuperHero() {} private Test.Base.Hero _hero;
[global::ProtoBuf.ProtoMember(, IsRequired = true, Name=@"hero", DataFormat = global::ProtoBuf.DataFormat.Default)]
public Test.Base.Hero hero
{
get { return _hero; }
set { _hero = value; }
}
private string _superSkill;
[global::ProtoBuf.ProtoMember(, IsRequired = true, Name=@"superSkill", DataFormat = global::ProtoBuf.DataFormat.Default)]
public string superSkill
{
get { return _superSkill; }
set { _superSkill = value; }
}
private global::ProtoBuf.IExtension extensionObject;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
{ return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
} }

下面我们看看工程中该如何使用生成的代码文件,先在VS中添加protobuf-net.dll的引用,文件在解压后的目录Full中,然后将生成的cs文件也包含到vs中。

下面是将对象序列化为二进制文件和从二进制文件中反序列化出对象的代码:

 using ProtoBuf;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Test.App;
using Test.Base; namespace ProtobufTest
{
class Program
{
static void Main(string[] args)
{
ObjectToFile();
FileToObject();
Console.ReadKey();
} private static void ObjectToFile()
{
//创建对象
SuperHero sh = new SuperHero();
sh.hero = new Hero();
sh.superSkill = "天狼巽闪"; sh.hero.people = new People();
sh.hero.skill = "疾鹰七痕剑"; sh.hero.people.name = "赛特";
sh.hero.people.sex = Sex.MALE;
sh.hero.people.age = ; //序列化
using(MemoryStream stream = new MemoryStream())
{
//获取二进制数据
Serializer.Serialize<SuperHero>(stream, sh);
byte[] bytes = stream.ToArray();
stream.Close(); //写入数据
using(FileStream fs = File.Open("D:\\test.bytes", FileMode.OpenOrCreate))
{
fs.Write(bytes, , bytes.Length);
fs.Flush();
fs.Close();
}
} Console.WriteLine("文件已经生成!");
} private static void FileToObject()
{
//读取数据
using(FileStream fs = File.Open("D:\\test.bytes", FileMode.Open))
{
byte[] bytes = new byte[fs.Length];
fs.Read(bytes, , (int)fs.Length);
fs.Close(); //反序列化
using(MemoryStream stream = new MemoryStream(bytes))
{
SuperHero sh = Serializer.Deserialize<SuperHero>(stream);
stream.Close(); Console.WriteLine("姓名:{0},性别:{1},年龄:{2},绝技:{3},终极绝技:{4}", sh.hero.people.name, sh.hero.people.sex, sh.hero.people.age, sh.hero.skill, sh.superSkill);
}
}
}
}
}

程序输出:

 文件已经生成!
姓名:赛特,性别:MALE,年龄:,绝技:疾鹰七痕剑,终极绝技:天狼巽闪

Protobuf-net学习笔记的更多相关文章

  1. gPRC学习笔记

    gPRC学习笔记 gPRC基础教程. gPRC官方文档. protobuf 3.0的简易教程. 什么是RPC RPC(remote procedure call) -- 远程过程调用(相对于本地调用的 ...

  2. Caffe学习笔记(一):Caffe架构及其模型解析

    Caffe学习笔记(一):Caffe架构及其模型解析 写在前面:关于caffe平台如何快速搭建以及如何在caffe上进行训练与预测,请参见前面的文章<caffe平台快速搭建:caffe+wind ...

  3. Caffe学习笔记4图像特征进行可视化

    Caffe学习笔记4图像特征进行可视化 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关注我的博客:http://blog.csdn.net/hit201 ...

  4. Caffe 学习笔记1

    Caffe 学习笔记1 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和 ...

  5. tensorflow学习笔记——模型持久化的原理,将CKPT转为pb文件,使用pb模型预测

    由题目就可以看出,本节内容分为三部分,第一部分就是如何将训练好的模型持久化,并学习模型持久化的原理,第二部分就是如何将CKPT转化为pb文件,第三部分就是如何使用pb模型进行预测. 一,模型持久化 为 ...

  6. kratos微服务框架学习笔记一(kratos-demo)

    目录 kratos微服务框架学习笔记一(kratos-demo) kratos本体 demo kratos微服务框架学习笔记一(kratos-demo) 今年大部分时间飘过去了,没怎么更博和githu ...

  7. Protocol Buffers学习笔记

    Protocol Buffers学习笔记 1. 简介 Protocol Buffers是google发明的一种数据交换格式,独立于语言,独立于平台.与其他的数据交换格式有所不同,Protocol Bu ...

  8. go微服务框架kratos学习笔记七(kratos warden 负载均衡 balancer)

    目录 go微服务框架kratos学习笔记七(kratos warden 负载均衡 balancer) demo demo server demo client 池 dao service p2c ro ...

  9. go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用)

    目录 go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用) warden direct demo-server gr ...

  10. kafka学习笔记(一)消息队列和kafka入门

    概述 学习和使用kafka不知不觉已经将近5年了,觉得应该总结整理一下之前的知识更好,所以决定写一系列kafka学习笔记,在总结的基础上希望自己的知识更上一层楼.写的不对的地方请大家不吝指正,感激万分 ...

随机推荐

  1. HeadFirst设计模式之模板方法模式

    一. 1.The Template Method defines the steps of an algorithm and allows subclasses to provide the impl ...

  2. Foreman--Puppet类导入

    一.Foreman环境: foreman建好后,系统默认创建了3个环境:production,development,common, 1. production: 在puppet.conf里已经定义其 ...

  3. 关于web会话中的session过期时间的设置

    关于web会话中的session过期时间的设置 1.操作系统: 步骤:开始——〉管理工具——〉Internet信息服务(IIS)管理器——〉网站——〉默认网站——〉右键“属性”——〉主目录——〉配置— ...

  4. Windows Embedded Compact 2013升级:VS2013也能编译

    IT之家(www.ithome.com):Windows Embedded Compact 2013升级:VS2013也能编译 今天,微软为Windows Embedded Compact 2013送 ...

  5. 【HDOJ】3828 A + B problem

    显然需要贪心,重叠越长越好,这样最终的串长尽可能短.需要注意的是,不要考虑中间结果,显然是个状态dp.先做预处理去重,然后求任意一对串的公共长度. /* 3828 */ #include <io ...

  6. Java面试题-并发容器和框架

    1. 如何让一段程序并发的执行,并最终汇总结果? 答:使用CyclicBarrier 和CountDownLatch都可以,使用CyclicBarrier 在多个关口处将多个线程执行结果汇总,Coun ...

  7. Compass 编译.scss文件的问题

    compass 命令编译scss文件存在一个问题: 不能对"_"下划线开头的scss文件名称的文件进行编译.将"_"去掉就可以啦

  8. CQOI2009中位数图

    原来在vijos上做过,当时根本看不懂 现在看起来这么水…… x记录从b向左连续走比k大的有多少个 y记录从b向右连续走比k大的有多少个 最后根据乘法原理乘一下 不过要加上x[0]+y[0]+1 因为 ...

  9. NOI2002robot

    这题又是纯数论题…… 独立数就是欧拉函数,政客和军人的含义已经说的很清楚了,学者是最多的…… 首先,如果我们知道了政客和军人的答案,那就只要用n的所有因子的欧拉函数值减去这两个值,然后取模就行了. 但 ...

  10. ehcache 分布式集群同步数据实例

    本文使用rmi方式,借鉴百度能搜到的文章,但是均不能做到数据同步,做了些改动完全没问题,更详细说明介绍百度即可.直奔主题,可运行的demo实例! 创建一个maven项目,配置pom pom.xml & ...