NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Framework/Net/NetTcp.cs

495 lines
15 KiB
C#
Raw Normal View History

2023-08-22 19:08:45 +08:00
//////////////////////////////////////////////////////////////////////////
//
// 文件Assets/Code/Scripts/Framework/Net/Base/NetTcp.cs
// 作者Xoen Xie
// 时间2023/07/01
// 描述TCP连接
// 说明:
//
//////////////////////////////////////////////////////////////////////////
using System;
using System.Net;
using System.Net.Sockets;
using UnityEngine;
namespace Framework
{
public class NetTcp
{
enum NetInfoType
{
None = 0,
Error,
Connected,
Data,
}
struct NetInfo
{
public NetInfoType type;
public byte[] data;
public NetError error;
}
enum NetState
{
None = 0,
Connecting,
Connected,
Close,
Release,
NetStateError,
}
// 客户端接受包最大大小32K
private const ushort MAX_BUFFER_SIZE = 1024 * 32;
private byte[] m_TempBuffer;
private byte[] m_RecvBuffer;
private byte[] m_LengthData;
private byte[] m_IDData;
private int m_nUintSize;
private int m_nBufferLength;
private Socket m_Socket;
private NetState m_nState;
private INetHandler m_Handler;
private NetWriter m_Writer;
private AsyncCallback m_AsyncConnect;
private AsyncCallback m_AsyncReceive;
private AsyncCallback m_AsyncSend;
private NetQueue<NetInfo> m_EventQueue;
public bool mIsConnected { get { return m_nState == NetState.Connected; } }
public NetTcp()
{
m_nState = NetState.None;
m_TempBuffer = new byte[MAX_BUFFER_SIZE];
m_RecvBuffer = new byte[MAX_BUFFER_SIZE];
m_nUintSize = sizeof(uint);
m_LengthData = new byte[4];
m_IDData = new byte[2];
m_nBufferLength = 0;
m_Writer = new NetWriter();
m_AsyncConnect = new AsyncCallback(OnEndConnect);
m_AsyncReceive = new AsyncCallback(OnEndReceive);
m_AsyncSend = new AsyncCallback(OnEndSend);
}
public bool Create(INetHandler handler)
{
m_Handler = handler;
m_EventQueue = new NetQueue<NetInfo>();
return true;
}
public void Release()
{
m_Handler = null;
Close();
m_nState = NetState.Release;
m_EventQueue = null;
}
2023-10-19 15:00:19 +08:00
public bool Connect(string ip,
int port)
2023-08-22 19:08:45 +08:00
{
2023-10-19 15:00:19 +08:00
if (DebugUtil.LogEnable)
DebugUtil.Log(string.Format("NetTcp.Connect Start Connect, ip={0}, port={1}", ip, port));
2023-08-22 19:08:45 +08:00
if (m_nState == NetState.Connecting || m_nState == NetState.Connected)
{
2023-10-19 15:00:19 +08:00
DebugUtil.LogWarning("NetTcp.Connect igone .... m_nState:{0}", m_nState);
2023-08-22 19:08:45 +08:00
return true;
}
try
{
IPAddress[] address = Dns.GetHostAddresses(ip);
for (int i = 0; i < address.Length; ++i)
2023-10-19 15:00:19 +08:00
{
if (DebugUtil.LogEnable)
{
DebugUtil.Log(string.Format("NetTcp.Connect Address:{0}, AddressFamily:{1}", address[i].ToString(), address[i].AddressFamily));
}
}
2023-08-22 19:08:45 +08:00
m_Socket = new Socket(address[0].AddressFamily, SocketType.Stream, ProtocolType.Tcp);
m_Socket.BeginConnect(address[0], port, m_AsyncConnect, null);
}
catch (Exception e)
{
2023-10-19 15:00:19 +08:00
DebugUtil.LogError("NetTcp::Connect caught a exception, message: {0}", e.Message);
2023-08-22 19:08:45 +08:00
Close();
PushEventError(NetError.Connect);
return false;
}
m_nState = NetState.Connecting;
return true;
}
2023-10-19 15:00:19 +08:00
public bool Send(ushort id,
byte[] data, uint nRawID)
2023-08-22 19:08:45 +08:00
{
if (m_nState != NetState.Connected)
return false;
m_Writer.Clear();
uint total = (uint)data.Length + 2 + 4;
m_Writer.WriteUInt(total);
m_Writer.WriteUShort(id);
m_Writer.WriteUInt(nRawID);
2023-08-22 19:08:45 +08:00
m_Writer.WriteBuffer(data);
int nSendSize = (int)m_Writer.Size;
byte[] sendData = new byte[nSendSize];
Array.Copy(m_Writer.Buffer, sendData, nSendSize);
try
{
m_Socket.BeginSend(sendData, 0, nSendSize, SocketFlags.None, m_AsyncSend, null);
}
catch (SocketException e)
{
if (e.ErrorCode == (int)SocketError.WouldBlock)
{
DebugUtil.LogWarning("NetTcp::Send SocketError.WouldBlock");
return true;
}
2023-10-19 15:00:19 +08:00
DebugUtil.LogError($"NetTcp::Send 1 caught a exception, error={0}, message={1}",e.ErrorCode, e.Message);
2023-08-22 19:08:45 +08:00
Close();
PushEventError(NetError.Send);
}
catch (Exception e)
{
2023-10-19 15:00:19 +08:00
DebugUtil.LogError("NetTcp::Send 2 caught a exception, message={0}", e.Message);
2023-08-22 19:08:45 +08:00
Close();
PushEventError(NetError.Send);
}
return true;
}
public void Receive()
{
if (m_nState != NetState.Connected)
return;
try
{
m_Socket.BeginReceive(m_RecvBuffer, m_nBufferLength, m_RecvBuffer.Length - m_nBufferLength, SocketFlags.None, m_AsyncReceive, null);
}
catch (SocketException e)
{
if (e.ErrorCode == (int)SocketError.WouldBlock)
{
DebugUtil.LogWarning("NetTcp::Receive SocketError.WouldBlock");
return;
}
2023-10-19 15:00:19 +08:00
DebugUtil.LogError("NetTcp::Receive 1 caught a exception, error={0}, message={1}", e.ErrorCode, e.Message);
2023-08-22 19:08:45 +08:00
Close();
PushEventError(NetError.Recv);
}
catch (Exception e)
{
2023-10-19 15:00:19 +08:00
DebugUtil.LogError("NetTcp::Receive 2 caught a exception, message={0}", e.Message);
2023-08-22 19:08:45 +08:00
Close();
PushEventError(NetError.Recv);
}
}
public void DisConnect()
{
if (m_nState != NetState.Connected && m_nState != NetState.Connecting)
return;
Close();
PushEventError(NetError.None);
}
private void Close()
{
if (m_nState == NetState.Release || m_nState == NetState.Close)
return;
m_nState = NetState.Close;
if (m_Socket != null)
{
try
{
DebugUtil.Log("NetTcp Close Shutdown");
m_Socket.Shutdown(SocketShutdown.Both);
}
catch
{
}
try
{
DebugUtil.Log("NetTcp Close Close");
m_Socket.Close();
}
catch
{
}
}
}
private void PushEventError(NetError error)
{
if (m_nState == NetState.Release || m_nState == NetState.None)
return;
NetInfo info;
info.type = NetInfoType.Error;
info.data = null;
info.error = error;
m_EventQueue.Push(info);
}
private void PushEventData(byte[] data)
{
if (m_nState == NetState.Release || m_nState == NetState.None)
return;
NetInfo info;
info.type = NetInfoType.Data;
info.data = data;
info.error = NetError.None;
m_EventQueue.Push(info);
}
private void PushEventConnected()
{
if (m_nState == NetState.Release || m_nState == NetState.None)
return;
NetInfo info;
info.type = NetInfoType.Connected;
info.data = null;
info.error = NetError.None;
m_EventQueue.Push(info);
}
public void Dispath()
{
if (m_nState == NetState.Release || m_nState == NetState.None)
{
return;
}
NetInfo info;
while (m_EventQueue != null && m_EventQueue.Pop(out info))
{
switch (info.type)
{
case NetInfoType.Connected:
m_Handler.OnConnected();
break;
case NetInfoType.Error:
m_Handler.OnError(info.error);
break;
case NetInfoType.Data:
m_Handler.OnRecv(info.data);
break;
}
}
}
private void OnEndConnect(IAsyncResult iar)
{
try
{
m_Socket.EndConnect(iar);
m_nState = NetState.Connected;
PushEventConnected();
DebugUtil.Log("NetTcp::OnEndConnect connected ...");
}
catch (Exception e)
{
2023-10-19 15:00:19 +08:00
DebugUtil.LogError("NetTcp::OnEndConnect caught a exception, message={0}", e.Message);
2023-08-22 19:08:45 +08:00
Close();
PushEventError(NetError.Connect);
return;
}
Receive();
}
private void OnEndSend(IAsyncResult iar)
{
if (m_nState != NetState.Connected)
return;
try
{
m_Socket.EndSend(iar);
}
catch (SocketException e)
{
if (e.ErrorCode == (int)SocketError.WouldBlock)
{
DebugUtil.LogWarning("NetTcp::OnEndSend SocketError.WouldBlock");
return;
}
2023-10-19 15:00:19 +08:00
DebugUtil.LogError("NetTcp::OnEndSend 1 caught a exception, error={0}, message={1}", e.ErrorCode, e.Message);
2023-08-22 19:08:45 +08:00
Close();
PushEventError(NetError.Send);
}
catch (Exception e)
{
2023-10-19 15:00:19 +08:00
DebugUtil.LogError("NetTcp::OnEndSend 2 caught a exception, message={0}", e.Message);
2023-08-22 19:08:45 +08:00
Close();
PushEventError(NetError.Send);
}
}
private void OnEndReceive(IAsyncResult iar)
{
if (m_nState != NetState.Connected)
return;
try
{
int nReceiveLength = m_Socket.EndReceive(iar);
2023-10-25 15:00:42 +08:00
if(nReceiveLength > 0)
{
OnReceiveData(nReceiveLength);
Receive();
}
else
{
Close();
PushEventError(NetError.Recv);
}
2023-08-22 19:08:45 +08:00
}
catch (SocketException e)
{
if (e.ErrorCode == (int)SocketError.WouldBlock)
{
DebugUtil.LogWarning("NetTcp::OnEndSend SocketError.WouldBlock");
return;
}
2023-10-19 15:00:19 +08:00
DebugUtil.LogError("NetTcp::OnEndReceive 1 caught a exception, error={0}, message={1}", e.ErrorCode, e.Message);
2023-08-22 19:08:45 +08:00
Close();
PushEventError(NetError.Recv);
return;
}
catch (Exception e)
{
2023-10-19 15:00:19 +08:00
DebugUtil.LogError("NetTcp::OnEndReceive 2 caught a exception, message={0}", e.Message);
2023-08-22 19:08:45 +08:00
Close();
PushEventError(NetError.Recv);
return;
}
2023-10-25 15:00:42 +08:00
2023-08-22 19:08:45 +08:00
}
2023-10-19 15:00:19 +08:00
private int GetPackageLength(byte[] buffer,
int startPos)
2023-08-22 19:08:45 +08:00
{
m_LengthData[0] = buffer[startPos];
m_LengthData[1] = buffer[startPos + 1];
m_LengthData[2] = buffer[startPos + 2];
m_LengthData[3] = buffer[startPos + 3];
return BitConverter.ToInt32(m_LengthData, 0);
}
private void OnReceiveData(int nReceiveLength)
{
// 总数据长度
int nTotalLen = m_nBufferLength + nReceiveLength;
2023-10-19 15:00:19 +08:00
if (nTotalLen <= m_nUintSize) // 数据太小
2023-08-22 19:08:45 +08:00
{
m_nBufferLength += nReceiveLength;
return;
}
int nPackageLen = GetPackageLength(m_RecvBuffer, 0);
if (nPackageLen < 2)
{
throw new NetPackageParseException();
}
// 如果总长度 < 数据长度+ 数据头, 说明数据还未接收完
if (nTotalLen < (int)(nPackageLen + m_nUintSize))
{
m_nBufferLength += nReceiveLength;
return;
}
2023-10-19 15:00:19 +08:00
else if (nTotalLen == nPackageLen + m_nUintSize) // 刚好收到一个包
2023-08-22 19:08:45 +08:00
{
byte[] packetData = new byte[nPackageLen];
Array.Copy(m_RecvBuffer, m_nUintSize, packetData, 0, nPackageLen);
PushEventData(packetData);
m_nBufferLength = 0;
return;
}
2023-10-19 15:00:19 +08:00
else // 收到了多个包,要把包都拆出来
2023-08-22 19:08:45 +08:00
{
2023-10-19 15:00:19 +08:00
Array.Copy(m_RecvBuffer, m_TempBuffer, nTotalLen); // 把已经接收到的数据备份一下
2023-08-22 19:08:45 +08:00
int nReadPos = 0;
while (true)
{
byte[] packetData = new byte[nPackageLen];
Array.Copy(m_TempBuffer, nReadPos + m_nUintSize, packetData, 0, nPackageLen);
PushEventData(packetData);
nReadPos += nPackageLen + m_nUintSize;
2023-10-19 15:00:19 +08:00
m_nBufferLength = nTotalLen - nReadPos; // 剩余数据长度
2023-08-22 19:08:45 +08:00
2023-10-19 15:00:19 +08:00
if (m_nBufferLength <= m_nUintSize) // 如果剩余的长度不够两个字节
2023-08-22 19:08:45 +08:00
{
2023-10-19 15:00:19 +08:00
Array.Copy(m_TempBuffer, nReadPos, m_RecvBuffer, 0, m_nBufferLength); // 把剩余的数据拷贝回去,等待下剩余的数据
2023-08-22 19:08:45 +08:00
break;
}
2023-10-19 15:00:19 +08:00
else // 如果超过四个字节
2023-08-22 19:08:45 +08:00
{
2023-10-19 15:00:19 +08:00
nPackageLen = GetPackageLength(m_TempBuffer, nReadPos); // 得到下一个包的数据长度
2023-10-24 13:36:37 +08:00
if (nPackageLen < 2)
2023-08-22 19:08:45 +08:00
{
throw new NetPackageParseException();
}
// 数据不够,继续去等待下一段数据
if (m_nBufferLength < nPackageLen + m_nUintSize)
{
Array.Copy(m_TempBuffer, nReadPos, m_RecvBuffer, 0, m_nBufferLength);
break;
}
}
}
}
}
}
}