Protobuf-net学习笔记
对于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学习笔记的更多相关文章
- gPRC学习笔记
gPRC学习笔记 gPRC基础教程. gPRC官方文档. protobuf 3.0的简易教程. 什么是RPC RPC(remote procedure call) -- 远程过程调用(相对于本地调用的 ...
- Caffe学习笔记(一):Caffe架构及其模型解析
Caffe学习笔记(一):Caffe架构及其模型解析 写在前面:关于caffe平台如何快速搭建以及如何在caffe上进行训练与预测,请参见前面的文章<caffe平台快速搭建:caffe+wind ...
- Caffe学习笔记4图像特征进行可视化
Caffe学习笔记4图像特征进行可视化 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关注我的博客:http://blog.csdn.net/hit201 ...
- Caffe 学习笔记1
Caffe 学习笔记1 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和 ...
- tensorflow学习笔记——模型持久化的原理,将CKPT转为pb文件,使用pb模型预测
由题目就可以看出,本节内容分为三部分,第一部分就是如何将训练好的模型持久化,并学习模型持久化的原理,第二部分就是如何将CKPT转化为pb文件,第三部分就是如何使用pb模型进行预测. 一,模型持久化 为 ...
- kratos微服务框架学习笔记一(kratos-demo)
目录 kratos微服务框架学习笔记一(kratos-demo) kratos本体 demo kratos微服务框架学习笔记一(kratos-demo) 今年大部分时间飘过去了,没怎么更博和githu ...
- Protocol Buffers学习笔记
Protocol Buffers学习笔记 1. 简介 Protocol Buffers是google发明的一种数据交换格式,独立于语言,独立于平台.与其他的数据交换格式有所不同,Protocol Bu ...
- go微服务框架kratos学习笔记七(kratos warden 负载均衡 balancer)
目录 go微服务框架kratos学习笔记七(kratos warden 负载均衡 balancer) demo demo server demo client 池 dao service p2c ro ...
- go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用)
目录 go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用) warden direct demo-server gr ...
- kafka学习笔记(一)消息队列和kafka入门
概述 学习和使用kafka不知不觉已经将近5年了,觉得应该总结整理一下之前的知识更好,所以决定写一系列kafka学习笔记,在总结的基础上希望自己的知识更上一层楼.写的不对的地方请大家不吝指正,感激万分 ...
随机推荐
- Delphi里的RTTI与反射(举例换掉FOnChange)
Delphi2010之后的RTTI做了很大休整,现在用起来很爽了哦.甚至可以获取某些类的内部私有单元,然后为其赋值!讲这个RTTI增强的,可以参考网上的多个博客内容,我列举一下:Delphi2010R ...
- 情人节红攻瑰--Delphi版本
在oschina上看到了用c写的红玫瑰, 以前只见过用js写的, 就随手用delphi翻译了c的代码, 效果还不错哈.... 原c作者jokeym贴子 http://www.oschina.net/c ...
- Android:requestWindowFeature应用程序窗体显示状态操作
注意requestWindowFeature必须在 setContentView()之前调用. 1.DEFAULT_FEATURES:系统默认状态,一般不需要指定 2.FEATURE_CONTEXT_ ...
- Android开发之Service的写法以及与Activity的通信
Service的总结: 1.按运行地点分类: 类别 区别 优点 缺点 应用 本地服务(Local) 该服务依附在主进程上, 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外 ...
- 【jQuery】
TryjQuery:jQuery官方推出的教学视频http://blog.jobbole.com/37699/ jQuery 1.11 / 2.1 beta 版发布,全面支持异步模块加载 √http ...
- 多线程程序设计学习(6)Producer-Consumer模式
Producer-Consumer[生产消费者模式]一:Producer-Consumer pattern的参与者--->产品(蛋糕)--->通道(传递蛋糕的桌子)--->生产者线程 ...
- 【转】IOS的处理touch事件处理(依照手指的移动移动一个圆,开发环境用的ios7,storyboard)-- 不错
原文网址:http://blog.csdn.net/baidu_nod/article/details/32934565 先看下页面的效果图: 首先定义这个ball它有两个属性和两个方法: @prop ...
- 【转】Android异步消息处理机制完全解析,带你从源码的角度彻底理解
原文网址:http://blog.csdn.net/guolin_blog/article/details/9991569 转载请注明出处:http://blog.csdn.net/guolin_bl ...
- (二)学习C#之内存管理
一.当你运行你的程序通常都会访问哪些内存空间呢? 电脑自言自语道,“这个人要声明一个整数”或“这个人个方法”或“这个人要创建一个对象” 1.这些信息究竟是存在内存里的什么地方呢? 2.或者说用于描述这 ...
- git提交小结
git有工作区和暂存区的概念,工作区就是可以看到文件目录的地方,暂存区则是提交代码的地方 第一步,进入文件工作目录,终端输入命令 $ dir1/dir2: 第二步,查看哪些文件已经修改,输入命令 $ ...