555 lines
17 KiB
C#
555 lines
17 KiB
C#
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
|
||
} |