版權聲明:本文為原創文章,轉載請聲明http://www.cnblogs.com/unityExplorer/p/6974229.html 近期在做一個棋牌項目,需要用到socket傳輸protobuf位元組流,在網上找了一些博客和文章後發現,沒有特別全面的,所以把自己研究的全部源碼拿出來和大家分享, ...
版權聲明:本文為原創文章,轉載請聲明http://www.cnblogs.com/unityExplorer/p/6974229.html
近期在做一個棋牌項目,需要用到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 //將流的位置設為0 16 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 test2 16 { 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 //將流的位置歸0 14 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文件
http://files.cnblogs.com/files/unityExplorer/protobuf-net.zip
預編譯和轉化工具
http://files.cnblogs.com/files/unityExplorer/protoGen.zip