这段时间琢磨了一下Unity3D网络游戏开发中的网络消息处理。网络游戏的服务端一般都是自主开发的,所以对应的网络消息处理也要自己开发。客户端/服务端之间的消息传到目前使用JSON和Google.ProtocolBuffers是两种常见的做法。打开炉石的代码看了看它的处理方式,感觉代码写的还是很好的,把它的思路分析一下,与大家分享。
炉石使用Google.ProtocolBuffers类库,可以看这里:http://www.nuget.org/packages/Google.ProtocolBuffers/
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; }
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); }
public abstract class PacketDecoder { // Methods public 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() { // Methods public override PegasusPacket HandlePacket(PegasusPacket p) { return ConnectAPI.PacketDecoder.HandleProtoBuf<TMessage, TBuilder>(p); } }