对于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. 12232 - Exclusive-OR

    12232 - Exclusive-OR 题目大意是可以设定一个点Xp=v,或者Xp^Xq=v,然后查询Xa^Xb^Xc...等于多少. 由于异或操作跟判连通性很类似,这里可以使用并查集来解决,对于X ...

  2. s3c6410 开发板Linux系统支持 K9GAG08U0E的方法

    由于NandFlash硬件升级比较快,公司去年一直在使用三星的K9GAG08U0D,现在MLC NandFlash 升级到了第二代,K9GAG08U0D 很快就会处在停产的状态,未雨绸缪,公司选型了K ...

  3. 八大Webkit内核浏览器

    列举出时下最流行的Webkit内核浏览器,所以我们并不会做出评测和对比.PS:本文列举的浏览器有一部分为IE+Webkit双核浏览器,如果您对其他IE内核浏览器很感兴趣<抛弃数据!用体验和感觉告 ...

  4. hdu4630No Pain No Game (多校3)(树状数组)

    http://acm.hdu.edu.cn/showproblem.php?pid=4630 给的题解没看懂..搜解题报告看 了N久  终于在cui大神的指点下 搞明白咋回事了 将1-N中的每个数ai ...

  5. poj 3009 Curling 2.0( dfs )

    题目:http://poj.org/problem?id=3009 参考博客:http://www.cnblogs.com/LK1994/ #include <iostream> #inc ...

  6. 请用一句话概括JSONP

    服务器调用客户端的函数(即回调函数),在客户端就能拿到服务端传入的参数(即返回结果)

  7. UVa 221 (STL 离散化) Urban Elevations

    题意: 作图为n个建筑物的俯视图,右图为从南向北看的正视图,按从左往右的顺序输出可见建筑物的标号. 分析: 题中已经说了,要么x相同,要么x相差足够大,不会出现精度问题. 给这n个建筑物从左往右排序, ...

  8. [POJ 1674] Sorting by Swapping

    Sorting by Swapping Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9514   Accepted: 50 ...

  9. js如何判断是手机端还是PC端访问

    function isMobile(){ var sUserAgent= navigator.userAgent.toLowerCase(), bIsIpad= sUserAgent.match(/i ...

  10. CentOS 7 安装 tomcat7.0

    安装tomcat: [root@admin local]# cd /usr/local[root@admin local]# tar -zxv -f apache-tomcat-7.0.29.tar. ...