对于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. centos安装异常解决方法

    VMware系统安装Centos7后,第一次启动出现以下异常信息: Initial setup of CentOS Linux (core) ) [x] Creat user ) [!] Licens ...

  2. P132、面试题21:包含min函数的栈

    实现思路:们需要一个辅助栈.每次push一个新元素的时候,同时将最小元素(或最小元素的位置.考虑到栈元素的类型可能是复杂的数据结构,用最小元素的位置将能减少空间消耗)push到辅助栈中:每次pop一个 ...

  3. PHP 的面向方面编程

    面向方面编程(AOP)对于PHP来说是一个新的概念.现在PHP对于 AOP 并没有官方支持,但有很多扩展和库实现了这个特性.本课中,我们将使用 Go! PHP library 来学习 PHP 如何进行 ...

  4. HTTP认证方式

    HTTP请求报头: Authorization HTTP响应报头: WWW-Authenticate   HTTP认证 基于 质询 /回应( challenge/response)的认证模式.   ◆ ...

  5. Tiny4412汇编流水灯代码,Tiny4412裸机LED操作[1]

    从今天开始就正式进入到tiny4412的开发学习中了,今天主要看了一下Tiny4412的启动流程及存储器映射及Exynos4412数据手册,用汇编写了一个跑马灯程序(后续会有C语言版本的出来),先说一 ...

  6. 在运行时切换 WinForm 程序的界面语言 System.ComponentModel.ComponentResourceManager .ApplyResources

    Download the code for this article: WinForm-Multilanguages-2.rar (11 KB). 方法二: 下面介绍一种只需对现有代码做较小改动的方法 ...

  7. pyqt实践——从裸机到打包安装

    1 安装python 安装python-2.7.6.msi默认在c盘 设置环境变量,path后追加c:/python27.可以在命令行直接认识命令python 2 安装pyqt PyQt4-4.10- ...

  8. Zend Framework XML外部实体和安全绕过漏洞

    漏洞版本: Zend Framework 1.x 漏洞描述: Bugtraq ID:66358 Zend Framework是一款开放源代码的PHP5开发框架实现. Zend Framework存在多 ...

  9. 体验Azure的 Automation “自动化” 服务预览版

    一直想要实现对Azure上跑的虚机进行定期的自动备份.在网上搜了一下有关的解决方案,发现一个不错的帖子,是基于国外的Azure服务做的.基本原理就是利用Azure的Automation(自动化)服务来 ...

  10. AngularJS 拦截器和好棒例子

    目录[-] 什么是拦截器? 异步操作 例子 Session 注入(请求拦截器) 时间戳(请求和响应拦截器) 请求恢复 (请求异常拦截) Session 恢复 (响应异常拦截器) 总结 Intercep ...