日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《炉石传说》建筑设计欣赏(7):采用Google.ProtocolBuffers处理网络消息

發布時間:2025/3/15 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《炉石传说》建筑设计欣赏(7):采用Google.ProtocolBuffers处理网络消息 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這一次,琢磨了一下Unity3D網絡游戲發展的網絡信息處理。服務器的網絡游戲一般都是自主研發,因此,相應的網絡消息處理應該培養自己。client/現在使用的郵件服務器之間的價差JSON和Google.ProtocolBuffers有兩種常見的方法。平爐碼看其處理。代碼寫的還是非常好的,把它的思路分析一下。與大家分享。

總體機制描寫敘述

我們想要達到的目標大概是這種:
  • 有N個網絡消息,每一個消息相應一個Proto中的message描寫敘述;
  • 每一個消息相應一個數字ID;
  • 底層在收到消息是,將其解析成為Google.ProtocolBuffers.IMessage對象,這個對象的詳細類型應該是前面那個message生成的代碼;
  • 發送消息就簡單了,由于知道其類型,能夠直接運行序列化。

爐石使用Google.ProtocolBuffers類庫,能夠看這里:http://www.nuget.org/packages/Google.ProtocolBuffers/

消息發送

發送的機制非常easy,首先使用ProtocolBuffer生成的message類構造一個消息對象,比如:ConnectAPI.SendPing() public static void SendPing() {Ping.Builder body = Ping.CreateBuilder();QueueGamePacket(0x73, body);s_lastGameServerPacketSentTime = DateTime.Now; } 底層會構造一個“PegasusPacket”數據包對象。加入到發送隊列之中,這個數據包對象主要包括3部分:消息ID。消息大小,詳細消息數據。詳見PegasusPacket.Encode()函數: public override byte[] Encode() {if (!(this.Body is IMessageLite)){return null;}IMessageLite body = (IMessageLite) this.Body;this.Size = body.SerializedSize;byte[] destinationArray = new byte[8 + this.Size];Array.Copy(BitConverter.GetBytes(this.Type), 0, destinationArray, 0, 4);Array.Copy(BitConverter.GetBytes(this.Size), 0, destinationArray, 4, 4);body.WriteTo(CodedOutputStream.CreateInstance(destinationArray, 8, this.Size));return destinationArray; }

消息接收與解析

接下來我們重點看一下消息的接收與解析機制。首先由于TCP是流式的。所以底層應該檢測數據包頭,并收集到一個完整的數據包,然后再發送到上層解析。這部分邏輯是在”ClientConnection<PacketType>.BytesReceived()“中實現的。

當收到完整數據包時。會在主線程中觸發”OnPacketCompleted“事件,實際上會調用到”ConnectAPI.PacketReceived()“,其內部主要是調用了”ConnectAPI.QueuePacketReceived()“,這個函數負責將TCP層接收到的byte[]解析成相應的IMessage對象。


重點來了!因為網絡層發過來的數據包,僅僅包括一個消息ID。那么client就須要解決從ID找到相應的消息Type的問題。

想象中無非有兩種方式去做:1是手動記錄每一個ID相應的Type;2是搞一個中間的相應關系的類,附加上自己定義的Attribute,然后在使用反射機制自己主動收集這些類,事實上和前者也差點兒相同。

爐石採用了第一種方式。總體機制是這種:

  • client每一個消息相應一個PacketDecoder的派生類對象;
  • ConnectAPI類使用一個字典,用來保存<消息ID,Decoder對象>之間的相應關系:ConnectAPI.s_packetDecoders:SortedDictionary<Int32,ConnectAPI.PacketDecoder>;
  • 假設每一個消息都要寫一個Decoder,而其內部代碼由全然一致,豈不是非常蛋疼?!

    好吧,我們用模板來實現,詳見興許分析;

  • 在ConnectAPI.ConnectInit()初始化的時候。創建Decoder對象。并保存到上述dict之中,類似這樣:
    ?s_packetDecoders.Add(0x74, new DefaultProtobufPacketDecoder<Pong, Pong.Builder>());
  • 最后在上述的收到完整數據包的函數中,依據數據包中記錄的消息ID。去查找Decoder。然后調用其方法得到詳細的消息對象。類似這樣:
    if (s_packetDecoders.TryGetValue(packet.Type, out decoder)){PegasusPacket item = decoder.HandlePacket(packet);if (item != null){queue.Enqueue(item);}}else{Debug.LogError("Could not find a packet decoder for a packet of type " + packet.Type);}
最后我們看一下,Decoder模板的實現技巧。首先消息解析的詳細操作是有Google.ProtocolBuffers生成的代碼去實現的,所以詳細操作流程是全然一致的。這些寫到基類的的靜態模板函數中: public abstract class PacketDecoder {// Methodspublic abstract PegasusPacket HandlePacket(PegasusPacket p);public static PegasusPacket HandleProtoBuf<TMessage, TBuilder>(PegasusPacket p) where TMessage: IMessageLite<TMessage, TBuilder> where TBuilder: IBuilderLite<TMessage, TBuilder>, new(){byte[] body = (byte[]) p.Body;TBuilder local2 = default(TBuilder);TBuilder local = (local2 == null) ? Activator.CreateInstance<TBuilder>() : default(TBuilder);p.Body = local.MergeFrom(body).Build();return p;} }其次。使用一個模板派生類,實現HandlePacket()這個虛函數,基本的目的僅僅是把TMessage和TBuilder這兩個類型傳給那個靜態函數而已: public class DefaultProtobufPacketDecoder<TMessage, TBuilder> : ConnectAPI.PacketDecoder where TMessage: IMessageLite<TMessage, TBuilder> where TBuilder: IBuilderLite<TMessage, TBuilder>, new() {// Methodspublic override PegasusPacket HandlePacket(PegasusPacket p){return ConnectAPI.PacketDecoder.HandleProtoBuf<TMessage, TBuilder>(p);} }
OK,爐石是使用使用ProtocolBuffers來處理網絡消息的機制就是這樣,是不是已經非常清晰啦!





版權聲明:本文博主原創文章,博客,未經同意不得轉載。

轉載于:https://www.cnblogs.com/blfshiye/p/4876797.html

總結

以上是生活随笔為你收集整理的《炉石传说》建筑设计欣赏(7):采用Google.ProtocolBuffers处理网络消息的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。