单词优化和整站优化,西安网站建设外包服务,在本地做的网站上传到空间之后_刷新就跳到本地的网址怎么办,十大短视频平台排行榜这一次#xff0c;琢磨了一下Unity3D网络游戏发展的网络信息处理。服务器的网络游戏一般都是自主研发#xff0c;因此#xff0c;相应的网络消息处理应该培养自己。client/现在使用的邮件服务器之间的价差JSON和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是流式的。所以底层应该检測数据包头并收集到一个完整的数据包然后再发送到上层解析。这部分逻辑是在”ClientConnectionPacketType.BytesReceived()“中实现的。当收到完整数据包时。会在主线程中触发”OnPacketCompleted“事件实际上会调用到”ConnectAPI.PacketReceived()“其内部主要是调用了”ConnectAPI.QueuePacketReceived()“这个函数负责将TCP层接收到的byte[]解析成相应的IMessage对象。 重点来了因为网络层发过来的数据包仅仅包括一个消息ID。那么client就须要解决从ID找到相应的消息Type的问题。想象中无非有两种方式去做1是手动记录每一个ID相应的Type2是搞一个中间的相应关系的类附加上自己定义的Attribute然后在使用反射机制自己主动收集这些类事实上和前者也差点儿相同。炉石採用了第一种方式。总体机制是这种 client每一个消息相应一个PacketDecoder的派生类对象ConnectAPI类使用一个字典用来保存消息IDDecoder对象之间的相应关系ConnectAPI.s_packetDecoders:SortedDictionaryInt32,ConnectAPI.PacketDecoder假设每一个消息都要写一个Decoder而其内部代码由全然一致岂不是非常蛋疼好吧我们用模板来实现详见兴许分析在ConnectAPI.ConnectInit()初始化的时候。创建Decoder对象。并保存到上述dict之中类似这样 s_packetDecoders.Add(0x74, new DefaultProtobufPacketDecoderPong, 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 HandleProtoBufTMessage, TBuilder(PegasusPacket p) where TMessage: IMessageLiteTMessage, TBuilder where TBuilder: IBuilderLiteTMessage, TBuilder, new(){byte[] body (byte[]) p.Body;TBuilder local2 default(TBuilder);TBuilder local (local2 null) ? Activator.CreateInstanceTBuilder() : default(TBuilder);p.Body local.MergeFrom(body).Build();return p;}
}其次。使用一个模板派生类实现HandlePacket()这个虚函数基本的目的仅仅是把TMessage和TBuilder这两个类型传给那个静态函数而已 public class DefaultProtobufPacketDecoderTMessage, TBuilder : ConnectAPI.PacketDecoder where TMessage: IMessageLiteTMessage, TBuilder where TBuilder: IBuilderLiteTMessage, TBuilder, new()
{// Methodspublic override PegasusPacket HandlePacket(PegasusPacket p){return ConnectAPI.PacketDecoder.HandleProtoBufTMessage, TBuilder(p);}
} OK炉石是使用使用ProtocolBuffers来处理网络消息的机制就是这样是不是已经非常清晰啦 版权声明本文博主原创文章博客未经同意不得转载。 转载于:https://www.cnblogs.com/blfshiye/p/4876797.html