工具前身:C# Protocol buffer 批处理工具
(该工具优化了经历了三个版本)
(其实还有V4版本,我还没上传,那个工具是重写后,更方便,现在在项目中使用,后面再上传)
现在这个版本就使用了Github上最新的:3.5.1版本(前两个版本都是:2.x的,无论是生成代码的速度、代码的运行效率,3.5.1都比2.x的高,IMessage取消了createBuilder/toBuilder,添加了:Parser,更加方便使用、更高效,该Protobuf版本的proto文件是使用proto3语法解释,部分proto1.x~2.x都不兼容了,具体看官方网吧,最主要的是protobuf3的protoc可以直接导出csharp代码了,之前2.x的是依靠一个:protogen的中间件来解析.protobin的方式,所以2.x生成csharp代码的效率大大降低了)
另附上Protocol buffer 官方网(需要科学上网),里面的教程、资源都最全面,需要的同学可看看
Protobuf encode(了解protobuf 是如何完成编码的也是很重要的,因为这个是protobuf的优点之一)
下载工具(完整的工程)(我开发时使用的是VS2015,其他VS版本的同学自行处理哦)
// 以下代码中的ProtoMap、Data1、等类都是由ProtobufGenBatTool生成的代码
static void usage()
{
// global parser
var parser = new Parser();
var d = new Data1() { Name = "test", Age = 18 };
// encode
var msgBuffer = parser.toMsgBuffer(d);
// decode method1:
var copy2 = parser.toMsg(ProtoMap.getPID(), msgBuffer);
d.Age = 20;
d.Name = "tony";
// encode
msgBuffer = parser.toMsgBuffer(d);
// decode method2:
var copy3 = parser.toMsg(ProtoMap.getPID(typeof(Data1)), msgBuffer);
// decode method3:
var copy4 = parser.toMsg(msgBuffer);
// dispose global parser
parser.Dispose();
Console.WriteLine(d.ToString() + copy2 + copy3 + copy4);
/*
Console:
{ "name": "tony", "age": 20 }{ "name": "test", "age": 18 }{ "name": "tony", "age": 20 }{ "name": "tony", "age": 20 }
Press any key to exit.
* */
}
整体的使用就是这么简单
如果要遍历Message字段,在proto3版本中也是很简单的(proto2的话,我就不想说了)
void test()
{
// 将上面的字段数据都打印一下:序号、名称、值
PrintMessage(d);
PrintMessage(copy2);
PrintMessage(copy3);
PrintMessage(copy4);
/*
Console:
Field 1 (name): tony
Field 2 (age): 20
Field 1 (name): test
Field 2 (age): 18
Field 1 (name): tony
Field 2 (age): 20
Field 1 (name): tony
Field 2 (age): 20
*/
}
public static void PrintMessage(IMessage message)
{
var descriptor = message.Descriptor;
foreach (var field in descriptor.Fields.InDeclarationOrder())
{
Console.WriteLine(
"Field {0} ({1}): {2}",
field.FieldNumber,
field.Name,
field.Accessor.GetValue(message));
}
}
相关的类有
ProtoMap.cs类的代码,该类是由:ProtobufGenBatTool工具生成
// Generated by the protocol buffer ProtobufGenBatTool. DO NOT EDIT!
using System;
using System.Collections.Generic;
using Google.Protobuf;
using com.net.protobuf.msg;
namespace com.net.protobuf.protomap
{
public static class ProtoMap
{
public static readonly Dictionary<int, Type> _s_pMapper1 = new Dictionary<int, Type>();
public static readonly Dictionaryint> _s_pMapper2 = new Dictionaryint>();
public static readonly Dictionary<int, MessageParser> _s_pMapper3 = new Dictionary<int, MessageParser>();
static ProtoMap()
{
_s_pMapper1[ 1 ] = typeof(Data1);
_s_pMapper1[ 2 ] = typeof(MyData);
_s_pMapper1[ 3 ] = typeof(MyRequest);
_s_pMapper1[ 4 ] = typeof(MyResponse);
_s_pMapper1[ 5 ] = typeof(Test);
_s_pMapper1[ 6 ] = typeof(DemoData);
_s_pMapper1[ 7 ] = typeof(DemoMyData);
_s_pMapper1[ 8 ] = typeof(DemoMyRequest);
_s_pMapper1[ 9 ] = typeof(DemoMyResponse);
_s_pMapper1[ 10 ] = typeof(DemoTest);
_s_pMapper1[ 11 ] = typeof(MPDemoTest);
_s_pMapper1[ 12 ] = typeof(MPDemoTest1);
_s_pMapper1[ 13 ] = typeof(MPDemoTest2);
_s_pMapper2[ typeof(Data1) ] = 1;
_s_pMapper2[ typeof(MyData) ] = 2;
_s_pMapper2[ typeof(MyRequest) ] = 3;
_s_pMapper2[ typeof(MyResponse) ] = 4;
_s_pMapper2[ typeof(Test) ] = 5;
_s_pMapper2[ typeof(DemoData) ] = 6;
_s_pMapper2[ typeof(DemoMyData) ] = 7;
_s_pMapper2[ typeof(DemoMyRequest) ] = 8;
_s_pMapper2[ typeof(DemoMyResponse) ] = 9;
_s_pMapper2[ typeof(DemoTest) ] = 10;
_s_pMapper2[ typeof(MPDemoTest) ] = 11;
_s_pMapper2[ typeof(MPDemoTest1) ] = 12;
_s_pMapper2[ typeof(MPDemoTest2) ] = 13;
_s_pMapper3[ 1 ] = Data1.Parser;
_s_pMapper3[ 2 ] = MyData.Parser;
_s_pMapper3[ 3 ] = MyRequest.Parser;
_s_pMapper3[ 4 ] = MyResponse.Parser;
_s_pMapper3[ 5 ] = Test.Parser;
_s_pMapper3[ 6 ] = DemoData.Parser;
_s_pMapper3[ 7 ] = DemoMyData.Parser;
_s_pMapper3[ 8 ] = DemoMyRequest.Parser;
_s_pMapper3[ 9 ] = DemoMyResponse.Parser;
_s_pMapper3[ 10 ] = DemoTest.Parser;
_s_pMapper3[ 11 ] = MPDemoTest.Parser;
_s_pMapper3[ 12 ] = MPDemoTest1.Parser;
_s_pMapper3[ 13 ] = MPDemoTest2.Parser;
}
public static Type getType(int pid)
{
return _s_pMapper1[pid];
}
public static int getPID(Type type)
{
return _s_pMapper2[type];
}
public static int getPID()
{
return _s_pMapper2[typeof(T)];
}
public static MessageParser getParser(int pid)
{
return _s_pMapper3[pid];
}
}
}
其他Parser编解码需要的类:
///
/// Parser for encode/deocde IMessage
/// author : Jave.Lin
/// date : 2018-03-19
///
class Parser : IDisposable
{
private MsgOutStream _m_pMsgOutStream;
private MemoryStream _m_pMs;
private bool _m_bDisposed;
public bool bDisposed { get { return _m_bDisposed; } }
public Parser() : this(null) { }
public Parser(MemoryStream pMs)
{
_m_pMs = _m_pMs ?? new MemoryStream();
_m_pMsgOutStream = new MsgOutStream(_m_pMs);
}
public void Dispose()
{
_m_bDisposed = true;
if (_m_pMsgOutStream != null)
{
_m_pMsgOutStream.Dispose();
_m_pMsgOutStream = null;
}
if (_m_pMs != null)
{
_m_pMs.Dispose();
_m_pMs = null;
}
}
public IMessage toMsg(int pid, MsgOutStream stream)
{
return toMsg(pid, stream.getBuffer(), 0, stream.getLen());
}
public IMessage toMsg(int pid, MsgBuffer msgBuffer)
{
return ProtoMap.getParser(pid).ParseFrom(msgBuffer.buffer, msgBuffer.idx, msgBuffer.len);
}
public IMessage toMsg(int pid, byte[] bytes, int idx, int len)
{
return ProtoMap.getParser(pid).ParseFrom(bytes, idx, len);
}
public IMessage toMsg(MsgBuffer msgBuffer) where T : IMessage
{
var pid = ProtoMap.getPID ();
return toMsg(pid, msgBuffer);
}
public IMessage toMsg(byte[] bytes, int idx, int len)
{
var pos = idx;
var pkLen = BitConverter.ToInt16(bytes, pos);
pos += 2;
var pid = BitConverter.ToInt32(bytes, pos);
pos += 4;
return toMsg(pid, bytes, pos, pkLen);
}
public MsgBuffer toMsgBuffer(IMessage msg)
{
_m_pMsgOutStream.clear();
_m_pMsgOutStream.push(msg);
return new MsgBuffer { buffer = _m_pMsgOutStream.getBuffer(), idx = 0, len = _m_pMsgOutStream.getLen() };
}
}
struct MsgBuffer
{
public byte[] buffer;
public int idx;
public int len;
}
class MsgOutStream : IDisposable
{
private CodedOutputStream _m_pCodeStream;
private MemoryStream _m_pMemoryStream;
private long _m_lLen;
private bool _m_bDisposed;
private bool _m_bOwnerd;
private object locker = new object();
public long lLen { get { return _m_lLen; } }
public bool bDisposed { get { return _m_bDisposed; } }
public MsgOutStream(MemoryStream pMemoryStream)
{
_m_pMemoryStream = pMemoryStream;
if (_m_pMemoryStream == null)
{
_m_pMemoryStream = new MemoryStream();
_m_bOwnerd = true;
}
_m_pCodeStream = new CodedOutputStream(_m_pMemoryStream, !_m_bOwnerd);
}
public void Dispose()
{
_m_bDisposed = true;
if (_m_pCodeStream != null)
{
_m_pCodeStream.Dispose();
_m_pCodeStream = null;
}
if (_m_bOwnerd)
{
if (_m_pMemoryStream != null)
{
_m_pMemoryStream.Dispose();
_m_pMemoryStream = null;
}
}
}
public void push(IMessage msg)
{
lock (locker)
{
msg.WriteTo(_m_pCodeStream);
_m_pCodeStream.Flush();
_m_lLen = _m_pMemoryStream.Position;
}
}
public void clear()
{
lock (locker)
{
_m_lLen = 0;
_m_pMemoryStream.Position = 0;
}
}
public byte[] getBuffer()
{
lock (locker)
{
return _m_pMemoryStream.GetBuffer();
}
}
public int getLen()
{
return (int)_m_lLen;
}
}