近期在做一个棋牌项目,需要用到socket传输protobuf字节流,在网上找了一些博客和文章后发现,没有特别全面的,所以把自己研究的全部源码拿出来和大家分享,因为刚开始做,可能会有不足的地方,欢迎拍砖~~
这一篇主要是protocol buffer文件的序列化和解析,废话不多说了,直接上干货
1 /// <summary> 2 /// 将消息序列化为二进制的方法 3 /// </summary> 4 /// <param name="model">要序列化的对象</param> 5 public static byte[] serialize(iextensible model) 6 { 7 try 8 { 9 //创建流对象10 memorystream ms = new memorystream()11 //使用protobuf自带的序列化工具序列化iextensible对象12 serializer.serialize<iextensible>(ms, model);13 //创建二级制数组,保存序列化后的流14 byte[] bytes = new byte[ms.length];15 //将流的位置设为016 ms.position = 0;17 //将流中的内容读取到二进制数组中18 ms.read(bytes, 0, bytes.length);19 return bytes;20 }21 catch (exception e)22 {23 debug.log(序列化失败: + e.tostring());24 return null;25 }26 }
protobuf文件中的每一条message经过protocol buffer提供的protogen工具可以转成c#的中的类,例如
message test { required string test1= 1; required string test2= 2; }
经过转化后就变成了
1 [global::system.serializable, global::protobuf.protocontract(name=@sedreq)] 2 public partial class test : global::protobuf.iextensible 3 { 4 public test() {} 5 6 private string _test1; 7 [global::protobuf.protomember(1, isrequired = true, name=@test1, dataformat = global::protobuf.dataformat.default)] 8 public string test1 9 {10 get { return _test1; }11 set { _test1 = value; }12 } 13 private string _test2;14 [global::protobuf.protomember(2, isrequired = true, name=@test2, dataformat = global::protobuf.dataformat.default)]15 public string test216 {17 get { return _test2; }18 set { _test2 = value; }19 }20 private global::protobuf.iextension extensionobject;21 global::protobuf.iextension global::protobuf.iextensible.getextensionobject(bool createifmissing)22 { return global::protobuf.extensible.getextensionobject(ref extensionobject, createifmissing); }23 }
无视所有带global的代码,你会发现,转化后的c#类和一个标准的c#实体类一模一样,并且,这些转化后的类都继承至protobuf.iextensible,所以上文中的序列化函数的参数的类型是iextensible
有了序列化,当然还需要反序列化,也就是讲byte[]反序列化为继承至iextensible的类型的对象
1 /// <summary> 2 /// 将收到的消息反序列化成iextensible对象 3 /// </summary> 4 /// <param name="msg">收到的消息的字节流.</param> 5 /// <returns></returns> 6 public static t deserialize<t>(byte[] bytes) where t : iextensible 7 { 8 try 9 {10 memorystream ms = new memorystream()11 //将消息写入流中12 ms.write(bytes, 0, bytes.length);13 //将流的位置归014 ms.position = 0;15 //反序列化对象16 t result = serializer.deserialize<t>(ms);17 return result;18 }19 catch (exception e)20 {21 debug.log(反序列化失败: + e.tostring());22 return null;23 }24 }
因为反序列化后的对象是继承至iextensible的类的对象,所以返回值必须使用泛型约束来定义,这样才能保证函数的通用性
工具搞定,接下来就是测试代码了
1 public void test()2 {3 test test = new test() { test1 = 123, test2 = 456 };4 byte[] bytes = serialize(test);5 test test2 = deserialize<test>(bytes);6 debug.log(test2.test1 + test2.test2);7 }
输出结果 123456
附上protobuf-net.dll文件
预编译和转化工具
以上就是socket传输protobuf字节流实例教程的详细内容。