/* Sog 游戏基础库 2016 by zouwei */ using System; using System.Net; using System.Text; using System.Collections.Generic; using Google.Protobuf.WellKnownTypes; using Google.Protobuf; namespace Sog { public class ProtoBufPacker : IProtoPacker { // todo 效率不高,换成数组 private Dictionary m_typeMessageParser = new Dictionary(); public ProtoBufPacker() { } //最小8 public int GetHeaderLength() { return 8; } public int GetFullHeaderLength() { return 16; } //打包头 public int PackHeader(MessageHeader header, byte[] headerBytes) { //小字节序 if(header.ObjectID == 0) { headerBytes[0] = (byte)(header.Length % 256); headerBytes[1] = (byte)(header.Length / 256); headerBytes[2] = (byte)(header.Type % 256); headerBytes[3] = (byte)(header.Type / 256); Span pbServerID = new Span(headerBytes, 4, 4); BitConverter.TryWriteBytes(pbServerID, header.ServerID); return 8; } else { headerBytes[0] = (byte)(header.Length % 256); headerBytes[1] = (byte)(header.Length / 256); //最高位置1 int newType = header.Type | 0x8000; headerBytes[2] = (byte)(newType % 256); headerBytes[3] = (byte)(newType / 256); Span pbServerID = new Span(headerBytes, 4, 4); BitConverter.TryWriteBytes(pbServerID, header.ServerID); Span pbObjectID = new Span(headerBytes, 8, 8); BitConverter.TryWriteBytes(pbObjectID, header.ObjectID); return 16; } } //解包头 public int UnPackHeader(byte[] data, int offset, int length, ref MessageHeader header) { int byte0 = data[offset + 0]; int byte1 = data[offset + 1]; int byte2 = data[offset + 2]; int byte3 = data[offset + 3]; header.Length = byte1 * 256 + byte0; header.Type = byte3 * 256 + byte2; header.ServerID = BitConverter.ToUInt32(data, offset + 4); bool haveObjectID = (header.Type & 0x00008000) > 0; if (!haveObjectID) { return 8; } //头有16字节 if (length < 16) { return 0; } //去掉最高位 header.Type &= 0x00007fff; header.ObjectID = BitConverter.ToInt64(data, offset + 8); return 16; } public virtual bool UnpackMessage(MessageData message, out RequestPacket packet) { try { MessageParser parser; m_typeMessageParser.TryGetValue(message.Header.Type,out parser); IMessage pbmessage = null; packet = new RequestPacket(message.Header.Type, message.Header.ObjectID, message.Header.ServerID); //现在工具用的还是class不是struct,之后看看要不要移动 //主要是message.Buffer.Data现在有缓存了,必须把message.Buffer.Length的正确长度传入 if (parser != null) { pbmessage = parser.ParseFrom(message.Buffer.Data, message.Buffer.Length); } else { TraceLog.Error("protobuf decode package type {0} error, can not find MessageParser,please register it first!" , message.Header.Type); return false; } packet.Message = pbmessage; //packet.MsgID = message.Header.Type; return true; } catch(Exception error) { TraceLog.Error("protobuf decode package type {0} error, {1}", message.Header.Type, error.Message); packet = null; } return false; } public virtual bool PackMessage(RequestPacket packet, ref MessageData message) { try { //这个基本不用了,这里不cache了 message.Buffer.Data = MessageExtensions.ToByteArray((IMessage)packet.Message); message.Buffer.Length = message.Buffer.Data.Length; message.Header.Length = message.Buffer.Data.Length; message.Header.Type = packet.MsgID; //校验一下消息id,需要注册,不注册返回失败 //校验类型是否匹配 //影响效率 if (TraceLog.GetLogLevel() <= Log.LogLevel.Trace) { if (OSUtils.IsWindows()) { MessageParser parser; m_typeMessageParser.TryGetValue(packet.MsgID, out parser); if (parser == null) { TraceLog.Error("protobuf encode package type {0} error, can not find MessageParser,please register it first!" , packet.MsgID); return false; } //windows下校验一下message是否会出问题 IMessage pbCheckMessage = parser.ParseFrom(message.Buffer.Data); if (pbCheckMessage.GetType() != packet.Message.GetType()) { TraceLog.Error("protobuf encode package type {0} error, Message type {1} != registed Message type {2}" , packet.MsgID, packet.Message.GetType().Name, pbCheckMessage.GetType().Name); return false; } } } return true; } catch (Exception error) { TraceLog.Error("protobuf encode package type {0} error, {1}", message.Header.Type, error.Message); packet = null; } return false; } //需要注册,提高效率 public void RegisterProtoType(int iMsgID, object obj) { MessageParser parser = (MessageParser)obj; if(m_typeMessageParser.ContainsKey(iMsgID)) { MessageParser oldparser = m_typeMessageParser[iMsgID]; TraceLog.Error("protobuf RegisterProtoType msgId {0} duplicate,registed name {1} new name {2}" , iMsgID, oldparser.GetType().Name, parser.GetType().Name); return; } m_typeMessageParser.Add(iMsgID, parser); } } }