using System; using System.IO; using System.Net; using UnityEngine; using zlib; namespace BF { /// /// @TODO GC /// internal class NetChannelMessageService : INetChannelMessageService { private readonly bool isLittleEndian; private readonly bool isCompress; private NetAesEncrypt encrypt; private NetAesEncrypt decrypt; /// /// 数据包的头部长度,version + Compress + Seq + Group + Cmd 共8位 /// private int HeaderLength => 4; /// /// 数据包头部长度,使用int类型表示,四个字节 /// private int HeaderLengthBytesSize => 4; public NetChannelMessageService() { isLittleEndian = BitConverter.IsLittleEndian; isCompress = false; } public void SetEncrypt(NetAesEncrypt encrypt) { this.encrypt = encrypt; } public void SetDecrypt(NetAesEncrypt decrypt) { this.decrypt = decrypt; } public int ReadBodyLength(CircularBuffer circularBuffer) { int bodyLength = 0; if (circularBuffer.HowManyCanRead >= HeaderLengthBytesSize) { byte[] head1 = circularBuffer.Read(HeaderLengthBytesSize); byte[] head = new byte[4]; head[0] = head1[3]; head[1] = head1[2]; head[2] = head1[1]; head[3] = head1[0]; bodyLength = BitConverter.ToInt32(head, 0); if (isLittleEndian) { bodyLength = IPAddress.NetworkToHostOrder(bodyLength); } if (bodyLength <= 0) { bodyLength = -1; } } return bodyLength; } public bool Serialize(NetOutgoingMessage message, MemoryStream destination) { try { //first write data package size, packageSize = header.length + data.length byte[] packageLengthData = null; // short packageLength = 0; int packageLength = 0; if (message.Group != 0) { // packageLength = (short)(message.PackDataLength + HeaderLength); packageLength = message.PackDataLength + HeaderLength*2; } else { // packageLength = (short)message.PackDataLength; packageLength = message.PackDataLength; } if (isLittleEndian) { packageLengthData = BitConverter.GetBytes(packageLength); } else { packageLengthData = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(packageLength)); } destination.Write(packageLengthData, 0, packageLengthData.Length); var realSendBuffer = SerializeRaw(message); //is need encrypt if (message.Group != 0) { if (encrypt == null) { throw new NotImplementedException("Serialize Error! NetAesEncrypt is null"); } encrypt.Encrypt(realSendBuffer, 0, realSendBuffer.Length, realSendBuffer, 0); } destination.Write(realSendBuffer, 0, realSendBuffer.Length); return true; } catch (Exception) { return false; } } internal byte[] SerializeRaw(NetOutgoingMessage message) { if (message.Group != 0) { byte[] realSendBuffer = new byte[message.PackDataLength + HeaderLength*2]; byte[] seqBytes = null; if (isLittleEndian) { seqBytes = BitConverter.GetBytes(message.Seq); } else { seqBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(message.Seq)); } Array.Copy(seqBytes, 0, realSendBuffer, 0, HeaderLength); //create send buffer if (BitConverter.IsLittleEndian) { realSendBuffer[7] = (byte)((message.Group >> 24) & 0xFF); realSendBuffer[6] = (byte)((message.Group >> 16) & 0xFF); realSendBuffer[5] = (byte)((message.Group >> 8) & 0xFF); realSendBuffer[4] = (byte)(message.Group & 0xFF); } else { realSendBuffer[4] = (byte)((message.Group >> 24) & 0xFF); realSendBuffer[5] = (byte)((message.Group >> 16) & 0xFF); realSendBuffer[6] = (byte)((message.Group >> 8) & 0xFF); realSendBuffer[7] = (byte)(message.Group & 0xFF); } //write data Array.Copy(message.Data, 0, realSendBuffer, HeaderLength*2, message.PackDataLength); return realSendBuffer; } else { //create send buffer byte[] realSendBuffer = new byte[message.PackDataLength]; Array.Copy(message.Data, 0, realSendBuffer, 0, message.PackDataLength); return realSendBuffer; } } /// /// @TODO Array GC /// /// /// public bool Deserialize(NetIncomingMessage message, uint receiveSeq) { try { decrypt.Decrypt(message.buffer, 0, message.buffer.Length, message.buffer, 0); DeserializeRaw(message, receiveSeq); if (message.IsCompress) { message.buffer = DeCompressBuffer(message.buffer); } return true; } catch (Exception) { return false; } } internal void DeserializeRaw(NetIncomingMessage message, uint receiveSeq) { //head // message.Version = message.buffer[0]; // message.IsCompress = message.buffer[1] != 0; // message.Group = message.buffer[2]; // message.CMD = message.buffer[3]; message.Group = (uint)(((message.buffer[7] & 0xFF) << 24) | ((message.buffer[6] & 0xFF) << 16) | ((message.buffer[5] & 0xFF) << 8) | (message.buffer[4] & 0xFF)); message.CMD = receiveSeq; var seq = BitConverter.ToInt32(message.buffer, 0); if (isLittleEndian) { message.Seq = (uint) seq; } else { message.Seq = (uint) IPAddress.NetworkToHostOrder(seq); } //data, @TODO only copy Array.Reverse(message.buffer); Array.Resize(ref message.buffer, message.buffer.Length - HeaderLength*2); Array.Reverse(message.buffer); } private byte[] DeCompressBuffer(byte[] byteArray) { using (MemoryStream outMemoryStream = new MemoryStream()) { using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream)) { using (Stream inMemoryStream = new MemoryStream(byteArray)) { byte[] buffer = new byte[inMemoryStream.Length]; int len; while ((len = inMemoryStream.Read(buffer, 0, buffer.Length)) > 0) { outZStream.Write(buffer, 0, len); } outZStream.Flush(); outZStream.finish(); return outMemoryStream.ToArray(); } } } } private byte[] CompressBuffer(byte[] byteArray) { using (MemoryStream outMemoryStream = new MemoryStream()) { using (ZInputStream zInputStream = new ZInputStream(outMemoryStream)) { using (Stream inMemoryStream = new MemoryStream(byteArray)) { byte[] buffer = new byte[inMemoryStream.Length]; int len; while ((len = inMemoryStream.Read(buffer, 0, buffer.Length)) > 0) { zInputStream.Read(buffer, 0, len); } inMemoryStream.Flush(); return outMemoryStream.ToArray(); } } } } } }