Files
JJBB/Assets/Project/Script/GameLogic/NetWork/NetWorkLogic.cs

555 lines
17 KiB
C#
Raw Normal View History

2024-08-23 15:49:34 +08:00
using System;
using System.Net;
using System.Threading;
using Google.ProtocolBuffers;
using Module.Log;
using SPacket.SocketInstance;
using UnityEngine;
public class NetWorkLogic
{
public delegate void ConnectDelegate(bool bSuccess, string result);
public delegate void ConnectLostDelegate();
public enum ConnectStatus
{
INVALID,
CONNECTING, //连接中
CONNECTED, //已连接
DISCONNECTED //已断连
}
public const uint SOCKET_ERROR = 0xFFFFFFFF;
public const int PACKET_HEADER_SIZE = sizeof(uint) + sizeof(ushort);
public const int MAX_ONE_PACKET_BYTE_SIZE = 1024; //单个收包默认1K缓存
public const int EACHFRAME_PROCESSPACKET_COUNT = 12;
private static ConnectDelegate m_delConnect;
private static ConnectLostDelegate m_delConnectLost;
private static NetWorkLogic m_Impl;
//收发包流量统计
public static int s_nReceiveCount;
public static int s_nSendCount;
//收发消息包状态
private bool m_bCanProcessPacket = true;
private bool m_bConnectFinish;
protected ConnectStatus m_connectStatus = ConnectStatus.INVALID;
//包头缓存
private readonly byte[] m_HeadbyteData;
private readonly byte[] m_LenbyteData;
private byte[] m_MaxRevOnePacketbyte;
//收包缓存
private int m_MaxRevOnePacketbyteCount;
private int m_nConnectSleep;
//每帧处理包的数量上限
private int m_nEachFrame_ProcessPacket_Count;
private byte m_nPacketIndex = 123;
private int m_nServerPort;
public static PacketFactoryManagerInstance m_PacketFactoryManager;
private readonly byte[] m_PacketIDbyteData;
//发包缓存
private readonly byte[] m_SendbyteData;
private readonly SocketInstance m_Socket;
private SocketInputStream m_SocketInputStream;
private SocketOutputStream m_SocketOutputStream;
private string m_strConnectResult = "";
private string m_strServerAddr;
private NetWorkLogic()
{
m_Socket = new SocketInstance();
m_PacketFactoryManager = new PacketFactoryManagerInstance();
m_hConnectThread = null;
m_PacketFactoryManager.Init();
m_SendbyteData = new byte[SocketOutputStream.DEFAULT_SOCKET_OUTPUT_BUFFER_SIZE]; //8K
m_LenbyteData = new byte[sizeof(int)];
m_PacketIDbyteData = new byte[sizeof(short)];
m_MaxRevOnePacketbyteCount = MAX_ONE_PACKET_BYTE_SIZE;
m_MaxRevOnePacketbyte = new byte[m_MaxRevOnePacketbyteCount];
m_HeadbyteData = new byte[PACKET_HEADER_SIZE];
m_nEachFrame_ProcessPacket_Count = EACHFRAME_PROCESSPACKET_COUNT;
}
public EndPoint GetLocalEndPoint()
{
return m_Socket.GetLocalEndPoint();
}
public bool CanProcessPacket
{
get { return m_bCanProcessPacket; }
set { m_bCanProcessPacket = value; }
}
public string GetIP()
{
return m_strServerAddr;
}
public int GetPort()
{
return m_nServerPort;
}
public static NetWorkLogic GetMe()
{
return m_Impl ?? (m_Impl = new NetWorkLogic());
}
public bool IsDisconnected()
{
return m_connectStatus == ConnectStatus.DISCONNECTED;
}
public void WaitConnected()
{
m_connectStatus = ConnectStatus.CONNECTING;
}
public ConnectStatus GetConnectStautus()
{
return m_connectStatus;
}
public static void SetConcnectDelegate(ConnectDelegate delConnectFun)
{
m_delConnect = delConnectFun;
}
public static void SetConnectLostDelegate(ConnectLostDelegate delFun)
{
m_delConnectLost = delFun;
}
// 重新构造发包和收包时机 - 发包时机会延后到LateUpdate最末尾
// 因此当前帧的包,会不等待渲染就发送
public void Update()
{
TickConnectFinish();
if (CheckSocketState())
WaitPacket();
}
public void LateUpdate()
{
if (CheckSocketState())
SendPacket();
}
/// <summary>
/// 检查是否已经连接完成
/// </summary>
private void TickConnectFinish()
{
if (m_bConnectFinish)
{
if (null != m_delConnect)
m_delConnect(m_connectStatus == ConnectStatus.CONNECTED, m_strConnectResult);
m_bConnectFinish = false;
}
}
/// <summary>
/// 检查Socket是否正常
/// </summary>
/// <returns></returns>
public bool CheckSocketState()
{
return m_Socket.IsValid && m_Socket.IsConnected;
}
private void Reset()
{
DisconnectServer();
}
public void ConnectLost()
{
m_connectStatus = ConnectStatus.DISCONNECTED;
if (null != m_delConnectLost) m_delConnectLost();
}
~NetWorkLogic()
{
DisconnectServer();
}
#region NetWork Process
public bool IsCryptoPacket(ushort nPacketID)
{
return nPacketID != (ushort) MessageID.PACKET_CG_LOGIN &&
nPacketID != (ushort) MessageID.PACKET_GC_LOGIN_RET &&
nPacketID != (ushort) MessageID.PACKET_CG_CONNECTED_HEARTBEAT &&
nPacketID != (ushort) MessageID.PACKET_GC_CONNECTED_HEARTBEAT;
}
private void SendPacket()
{
try
{
ProcessOutput();
}
catch (Exception ex)
{
LogModule.ErrorLog(ex.ToString());
}
}
private void WaitPacket()
{
try
{
if (!ProcessInput())
return;
ProcessPacket();
}
catch (Exception ex)
{
LogModule.ErrorLog(ex.ToString());
}
}
private bool ProcessInput()
{
if (m_SocketInputStream == null)
return false;
if (m_Socket.IsCanReceive() == false)
return true;
var nSizeBefore = m_SocketInputStream.Length();
var ret = m_SocketInputStream.Fill();
var nSizeAfter = m_SocketInputStream.Length();
if (ret == SOCKET_ERROR)
{
LogModule.ErrorLog("recieve packet fail ProcessInput");
m_Socket.close();
ConnectLost();
return false;
}
//收包统计
if (nSizeAfter > nSizeBefore)
{
if (s_nReceiveCount < 0)
s_nReceiveCount = 0;
s_nReceiveCount += (int) (nSizeAfter - nSizeBefore);
}
return true;
}
private bool ProcessOutput()
{
if (m_SocketOutputStream == null)
return false;
if (m_Socket.IsCanSend() == false)
return true;
var ret = m_SocketOutputStream.Flush();
if (ret == SOCKET_ERROR)
{
LogModule.ErrorLog("send packet fail ProcessOutput");
m_Socket.close();
ConnectLost();
return false;
}
return true;
}
//User buffer to push data
private void ProcessPacket()
{
if (m_SocketInputStream == null)
return;
var nProcessPacketCount = m_nEachFrame_ProcessPacket_Count;
int packetSize;
short messageid;
Ipacket pPacket = null;
while (m_bCanProcessPacket && nProcessPacketCount-- > 0)
{
Array.Clear(m_HeadbyteData, 0, PACKET_HEADER_SIZE);
if (!m_SocketInputStream.Peek(m_HeadbyteData, PACKET_HEADER_SIZE))
break;
packetSize = BitConverter.ToInt32(m_HeadbyteData, 0);
packetSize = IPAddress.NetworkToHostOrder(packetSize);
messageid = BitConverter.ToInt16(m_HeadbyteData, sizeof(uint));
messageid = IPAddress.NetworkToHostOrder(messageid);
//LogModule.DebugLog("ProcessPacket rev msgID:" + messageid);
if (packetSize <= 0 || messageid <= 0)
LogModule.ErrorLog("ProcessPacket packetSize: " + packetSize + " messageid : " + messageid +
" HeadDate: " + LogModule.ByteToString(m_HeadbyteData, 0, PACKET_HEADER_SIZE));
if (m_SocketInputStream.Length() < packetSize)
break;
try
{
if (m_MaxRevOnePacketbyteCount < packetSize)
{
m_MaxRevOnePacketbyte = new byte[packetSize];
m_MaxRevOnePacketbyteCount = packetSize;
}
Array.Clear(m_MaxRevOnePacketbyte, 0, m_MaxRevOnePacketbyteCount);
var bRet = m_SocketInputStream.Skip(PACKET_HEADER_SIZE);
if (bRet == false)
{
var errorLog = string.Format("Can not Create Packet MessageID({0},packetSize{1})", messageid,
packetSize);
throw PacketException.PacketReadError(errorLog);
}
m_SocketInputStream.Read(m_MaxRevOnePacketbyte, (uint) (packetSize - PACKET_HEADER_SIZE));
if (IsCryptoPacket((ushort) messageid))
XorCrypto.XorDecrypt(m_MaxRevOnePacketbyte, (uint) (packetSize - PACKET_HEADER_SIZE));
//pPacket = m_PacketFactoryManager.GetPacketHandler((MessageID) messageid);
//if (pPacket == null)
//{
// var errorLog = string.Format("Can not Create Packet MessageID({0},buff{1})", messageid,
// LogModule.ByteToString(m_MaxRevOnePacketbyte, 0, m_MaxRevOnePacketbyteCount));
// throw PacketException.PacketCreateError(errorLog);
//}
var realPacket = PacketDistributed.CreatePacket((MessageID) messageid);
if (realPacket == null)
{
var errorLog = string.Format("Can not Create Inner Packet Data MessageID({0},buff{1})", messageid,
LogModule.ByteToString(m_MaxRevOnePacketbyte, 0, m_MaxRevOnePacketbyteCount));
throw PacketException.PacketCreateError(errorLog);
}
var instancePacket = realPacket.ParseFrom(m_MaxRevOnePacketbyte, packetSize - PACKET_HEADER_SIZE);
if (instancePacket == null)
{
var errorLog = string.Format("Can not Merged Inner Packet Data MessageID({0},buff{1})", messageid,
LogModule.ByteToString(m_MaxRevOnePacketbyte, 0, m_MaxRevOnePacketbyteCount));
throw PacketException.PacketCreateError(errorLog);
}
NetManager.Instance().AddPacketInstance(instancePacket);
//#if UNITY_EDITOR
// MarkNetMessage.MarkMessage(((MessageID)messageid).ToString().ToUpper(), packetSize);
//#endif
//GuiTextDebug.debug("RecivePacket:" + pPacket.ToString());
//Profiler.BeginSample((MessageID)messageid+"");
//var result = pPacket.Execute(instancePacket);
////Profiler.EndSample();
//if ((PACKET_EXE) result != PACKET_EXE.PACKET_EXE_NOTREMOVE)
//{
// m_PacketFactoryManager.RemovePacket(pPacket);
//}
//else if ((PACKET_EXE) result == PACKET_EXE.PACKET_EXE_ERROR)
//{
// var errorLog = string.Format("Execute Packet error!!! MessageID({0},buff{1})", messageid,
// LogModule.ByteToString(m_MaxRevOnePacketbyte, 0, m_MaxRevOnePacketbyteCount));
// throw PacketException.PacketExecuteError(errorLog);
//}
}
catch (PacketException ex)
{
LogModule.ErrorLog(ex.ToString());
}
catch (Exception ex)
{
LogModule.ErrorLog(ex.ToString());
}
}
if (nProcessPacketCount >= 0)
m_nEachFrame_ProcessPacket_Count = EACHFRAME_PROCESSPACKET_COUNT;
else
m_nEachFrame_ProcessPacket_Count += 4;
}
public void SendPacket(PacketDistributed pPacket)
{
if (pPacket == null)
return;
//scut
//NetWriter.SetUrl("192.168.1.163:9001");
//ActionParam param = new ActionParam();
//param._Packet = pPacket;
//LogModule.DebugLog("SendMessage" + pPacket.GetPacketID());
//Net.Instance.Send((int)pPacket.GetPacketID(), null, param);
if (m_connectStatus != ConnectStatus.CONNECTED)
{
if (m_connectStatus == ConnectStatus.DISCONNECTED)
{
// 再次询问断线重连情况
LogModule.ErrorLog("DISCONNECTED SendPacket");
ConnectLost();
}
return;
}
if (m_Socket.IsValid)
{
if (!pPacket.IsInitialized())
throw InvalidProtocolBufferException.ErrorMsg("Request data have not set");
var nValidbyteSize = pPacket.SerializedSize();
//if (nValidbyteSize <= 0)
//{
// return;
//}
//Array.Clear(m_SendbyteData, 0, (int)SocketOutputStream.DEFAULT_SOCKET_OUTPUT_BUFFER_SIZE); 不用全部清理,用多少清多少吧
var nClearCount = nValidbyteSize + 128;
if (nClearCount > (int) SocketOutputStream.DEFAULT_SOCKET_OUTPUT_BUFFER_SIZE)
nClearCount = (int) SocketOutputStream.DEFAULT_SOCKET_OUTPUT_BUFFER_SIZE;
Array.Clear(m_SendbyteData, 0, nClearCount);
var output = CodedOutputStream.CreateInstance(m_SendbyteData, 0, nValidbyteSize);
pPacket.WriteTo(output);
output.CheckNoSpaceLeft();
var nlen = nValidbyteSize + PACKET_HEADER_SIZE;
var netnlen = IPAddress.HostToNetworkOrder(nlen);
var messageid = IPAddress.HostToNetworkOrder((short) pPacket.GetPacketID());
Array.Clear(m_LenbyteData, 0, sizeof(int));
Array.Clear(m_PacketIDbyteData, 0, sizeof(short));
m_LenbyteData[0] = (byte) netnlen; //小端顺序放
m_LenbyteData[1] = (byte) (netnlen >> 8);
m_LenbyteData[2] = (byte) (netnlen >> 16);
m_LenbyteData[3] = (byte) (netnlen >> 24);
m_PacketIDbyteData[0] = (byte) messageid;
m_PacketIDbyteData[1] = (byte) (messageid >> 8);
var nSizeBefore = m_SocketOutputStream.Length();
m_SocketOutputStream.Write(m_LenbyteData, sizeof(int));
m_SocketOutputStream.Write(m_PacketIDbyteData, sizeof(short));
if (IsCryptoPacket((ushort) pPacket.GetPacketID()))
XorCrypto.XorEncrypt(m_SendbyteData, (uint) nValidbyteSize);
m_SocketOutputStream.Write(m_SendbyteData, (uint) nValidbyteSize);
var nSizeAfter = m_SocketOutputStream.Length();
//发包统计
if (nSizeAfter > nSizeBefore)
{
if (s_nSendCount < 0)
s_nSendCount = 0;
s_nSendCount += (int) (nSizeAfter - nSizeBefore);
}
}
else
{
LogModule.ErrorLog("DISCONNECTED SendPacket m_Socket.IsValid");
ConnectLost();
}
}
#endregion
#region Common Service
public void ConnectToServer(string szServerAddr, int nServerPort, int nSleepTime)
{
if (m_connectStatus == ConnectStatus.CONNECTING)
return;
m_strServerAddr = szServerAddr;
m_nServerPort = nServerPort;
m_nConnectSleep = nSleepTime;
m_hConnectThread = new Thread(_ConnectThread);
m_timeConnectBegin = Time.time;
m_hConnectThread.Start(this);
}
public void ReConnectToServer()
{
if (m_connectStatus == ConnectStatus.CONNECTING)
return;
if (m_SocketInputStream != null)
m_SocketInputStream.CleanUp();
if (m_SocketOutputStream != null)
m_SocketOutputStream.CleanUp();
m_hConnectThread = new Thread(_ConnectThread);
m_timeConnectBegin = Time.time;
m_hConnectThread.Start(this);
}
public void DisconnectServer()
{
if (m_strServerAddr == null || m_strServerAddr.Length == 0)
return;
m_Socket.close();
m_connectStatus = ConnectStatus.DISCONNECTED;
}
#endregion
//////////////////////////////////////////////////////////////////////////
#region Thread For Connect
public void ConnectThread()
{
m_connectStatus = ConnectStatus.CONNECTING;
while (true)
{
m_Socket.close();
//LogModule.DebugLog("connect:" + m_strServerAddr);
//Console.WriteLine("connect:" + m_strServerAddr);
m_strConnectResult = m_Socket.connect(m_strServerAddr, m_nServerPort);
if (m_strConnectResult.Length == 0 && m_Socket.IsValid)
{
m_SocketInputStream = new SocketInputStream(m_Socket);
m_SocketOutputStream = new SocketOutputStream(m_Socket);
m_connectStatus = ConnectStatus.CONNECTED;
break;
}
LogModule.WarningLog(m_strConnectResult);
m_Socket.close();
Thread.Sleep(m_nConnectSleep);
m_connectStatus = ConnectStatus.DISCONNECTED;
break;
}
m_bConnectFinish = true;
}
protected static void _ConnectThread(object me)
{
var rMe = me as NetWorkLogic;
rMe.ConnectThread();
}
private Thread m_hConnectThread;
private float m_timeConnectBegin;
#endregion
}