c1_unity/Assets/Scripts/Common/Network/Base/Impl/NetChannelMessageService.cs
2023-04-03 11:04:31 +08:00

270 lines
9.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.IO;
using System.Net;
using UnityEngine;
using zlib;
namespace BF
{
/// <summary>
/// @TODO GC
/// </summary>
internal class NetChannelMessageService : INetChannelMessageService
{
private readonly bool isLittleEndian;
private readonly bool isCompress;
private NetAesEncrypt encrypt;
private NetAesEncrypt decrypt;
/// <summary>
/// 数据包的头部长度version + Compress + Seq + Group + Cmd 共8位
/// </summary>
private int HeaderLength => 4;
/// <summary>
/// 数据包头部长度使用int类型表示四个字节
/// </summary>
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;
}
}
/// <summary>
/// @TODO Array GC
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
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();
}
}
}
}
}
}