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(); } /// /// 检查是否已经连接完成 /// private void TickConnectFinish() { if (m_bConnectFinish) { if (null != m_delConnect) m_delConnect(m_connectStatus == ConnectStatus.CONNECTED, m_strConnectResult); m_bConnectFinish = false; } } /// /// 检查Socket是否正常 /// /// 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 }