在網絡通訊中應用Protobuf


     Protobuf的設計非常適用於在網絡通訊中的數據載體,它序列化出來的數據量少再加上以K-V的方式來存儲數據,對消息的版本兼容性非常強;還有一個比較大的優點就是有着很多的語言平台支持。下面講解一下如何在TCP通訊應用中集成Protobuf.

     Protobuf提供一種簡單的對象消息方式來描述數據的存儲,通過相關實現可以簡單地實現數據流和對象之間的轉換。但由於Protobuf序列化后的信息並不包括一些相應對象類型描述,只有消息體的內容;因此在進行通信交互過程中默認情況是不知道這些數據和對象的對應關系;既然對方不清楚這些數據對應那種類型,那數據還源成對象就根本沒辦法入手。所以把Protobuf用到網絡通訊中我們還需要外加一些協議來規范數據的對應關系。

     在通訊協議上只需要在消息體中先寫入類型然后再寫入Protobuf數據,TypeName主要是用於對方配匹數據對應的對象關系,這個TypeName是string還是int或其他就根據自己喜好來制定了。

     在通訊上問題就解決了,但還要面對實際中使用的一種情況消息太多了……那處理TypeName->Object則一個蛋痛的事情。還好在.net和android下有類元素表這玩意還能在運行行進行操作,從而可以大大節省這些if判斷處理。由於本人熟悉的語言平台有限,在這里分別提供java和c#的解決方法。

  • Java
public static void Register(Class<?> protobufclass) {
		try {
			ProtoMessageHandler mb;
			Class<?>[] protoObjs = protobufclass.getClasses();
			for (Class<?> item : protoObjs) {
				if(item==null)
					continue;
				if (!item.isInterface() && item.getSuperclass().equals(
						com.google.protobuf.GeneratedMessage.class)) {
					mb = new ProtoMessageHandler();
					mb.SetType(item);
					mMessageTbl.put(item.getSimpleName(), mb);
				}
			}
		} catch (Exception e) {
			
			
		}

	}

     由於使用Protoc工具生成的類都會生成一個大類里,所以只需要注冊指定的類然后對所有繼承com.google.protobuf.GeneratedMessage的內嵌類找出來並記錄在一個Map中即可。

String name= stream.ReadUTF();
		ProtoMessageHandler handler = ProtoPackage.GetMsgHandler(name);
		if(handler==null)
			throw new Exception(name+" message type notfound!");
		Message=(com.google.protobuf.GeneratedMessage) handler.GetObject(stream.GetStream());

     以上是通過類型值獲取對應的對象,並填充Protobuf數據。

  • c#

     相對於android平台下的實現,.net的實現就更簡單些了。

public static void Register(System.Reflection.Assembly assembly)
        {
            foreach(Type type in assembly.GetTypes())
            {
                if (!type.IsAbstract && !type.IsInterface && type.GetCustomAttributes(typeof(ProtoBuf.ProtoContractAttribute), false).Length > 0)
                    mProtoTbl[type.Name] = type;
            }
        }
string name = reader.ReadUTF();
            Type type = ProtoPakcage.GetProtoType(name);
            Message = ProtoBuf.Meta.RuntimeTypeModel.Default.Deserialize(reader.Stream, null, type);

     通過以上方法在使用Protobuf的時候就不用擔心消息太多寫if寫到手軟了,也不容易出錯。不過有一點要注意的就是類的名稱一定要對應,否則就無法匹配到消息了。如果想得到完全整的代碼可以到https://beetlenp.codeplex.com獲取。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM