Files
JJBB/Assets/Project/Script/GameLogic/NetWork/NetWorkLogic.cs
2024-08-23 15:49:34 +08:00

555 lines
17 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.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
}