using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using SystemX.Common; using SystemX.Common.Serialization; using SystemX.Net.Comm; //using static SystemX.Net.Platform.Common.Util.LogMessage; namespace SystemX.Net.Comm { public class AsyncServerSocket : SystemXSocket, IDisposable { private Socket ServerSock; private IPAddress SetAddress; //Unused private Socket ClientSock; /* client Socket */ //private Socket cbClientSock; /* client Async Callback Socket */ private byte[] recvBuffer; //private String recvText; private byte[] recvStoreBuffer; private int iStoreCnt; private int iCheckRetryCnt; private const int MAX_CHECK_COUNT = 100; /* 256000 / 4096 <- 65526 / 4096 */ private const int USER_MAX_SIZE = 819200; /* 256000 <- 1000000 65536 */ private const int MAXSIZE = 8192; /* 8192 <- 4096 */ private string m_strGetIp; private int m_iGetPort; private bool m_bOpen; private bool m_bConnected; private string m_strGetText; private bool m_bGetRecv; public override event SocketCallEvent Comm_Connect_Event; public override event SocketCallEvent Socket_Error_Event; public override event SendRecvCallEvent Comm_Send_Event; public override event SendRecvCallEvent Comm_Recv_Event; private Queue QPacketAllData; private Queue QPacketRemainData; private bool bQueuePacketClearOn; public override void SetRefSocketPacketClear() { bQueuePacketClearOn = true; } private bool bDisposed; // //private bool bHaveHostinfo; //private DataTable dtHostInfo; public bool STATE { get { return this.m_bOpen; } } public bool CLIENT_CONNECT { get { return this.m_bConnected; } } public string MSG { set { this.m_strGetText = value; } get { return this.m_strGetText; } } public bool RECV_STATE { set { this.m_bGetRecv = value; } get { return this.m_bGetRecv; } } public string strSetRemoteAddress { set; get; } public string strSetRemotePort { set; get; } /* public bool HAVE_HOST_INFO { set { this.bHaveHostinfo = value; } get { return this.bHaveHostinfo; } } */ public AsyncServerSocket(SOCKET_TYPE SOCK_TYPE, int iCreatePosition, IPEndPoint SetRemote) : base(SOCKET_RULE.SERVER, SOCK_TYPE) { bDisposed = false; QPacketAllData = new Queue(); QPacketRemainData = new Queue(); bQueuePacketClearOn = false; strSetRemoteAddress = string.Empty; strSetRemotePort = string.Empty; SetAddress = SetRemote.Address; nSocketNumber = iCreatePosition; m_strGetIp = SetRemote.Address.ToString(); m_iGetPort = SetRemote.Port; ServerSock = null; ClientSock = null; //cbClientSock = null; //recvText = string.Empty; recvStoreBuffer = new byte[USER_MAX_SIZE]; iStoreCnt = 0; iCheckRetryCnt = 0; recvBuffer = new byte[MAXSIZE]; // m_bGetRecv = false; m_bOpen = false; m_bConnected = false; SetSocketListen(); } public AsyncServerSocket(SOCKET_TYPE SOCK_TYPE, int iCreatePosition, IPEndPoint SetRemote, DataTable dtHostInfomation) : base(SOCKET_RULE.SERVER, SOCK_TYPE) { bDisposed = false; strSetRemoteAddress = string.Empty; strSetRemotePort = string.Empty; SetAddress = SetRemote.Address; nSocketNumber = iCreatePosition; m_strGetIp = SetRemote.Address.ToString(); m_iGetPort = SetRemote.Port; ServerSock = null; ClientSock = null; //cbClientSock = null; //recvText = string.Empty; recvStoreBuffer = new byte[USER_MAX_SIZE]; iStoreCnt = 0; iCheckRetryCnt = 0; recvBuffer = new byte[MAXSIZE]; // m_bGetRecv = false; m_bOpen = false; m_bConnected = false; SetSocketListen(); } protected override void Dispose(bool disposing) { if (!bDisposed) { ConnectTokken.SetTokenState((ConnectTokken.Connect_Token)nSocketNumber, false); try { if (ServerSock != null) { if (ServerSock.Connected) ServerSock.Shutdown(SocketShutdown.Both); ServerSock.Close(); //ServerSock.Dispose(); ServerSock = null; } m_bOpen = false; ClientSock = null; m_bConnected = false; } catch (Exception e) { ClientSock = null; ServerSock = null; m_bOpen = false; m_bConnected = false; ErrorEventProcess(new Exception("Dispose failed. [SystemX.Net.Comm : AsyncServerSocket.Dispose]")); } finally { /* ClearEventConnectCall(); ClearEventErrorCall(); */ ClearEventSendCall(); ClearEventRecvCall(); } if (disposing) { //Manage } //Unmanage recvStoreBuffer = null; recvBuffer = null; bDisposed = true; } //Base Dispose base.Dispose(disposing); } public void ClearEventConnectCall() { if (Comm_Connect_Event != null) { foreach (Delegate d in Comm_Connect_Event.GetInvocationList()) Comm_Connect_Event -= (SocketCallEvent)d; } } public void ClearEventErrorCall() { if (Socket_Error_Event != null) { foreach (Delegate d in Socket_Error_Event.GetInvocationList()) Socket_Error_Event -= (SocketCallEvent)d; } } public void ClearEventSendCall() { if (Comm_Send_Event != null) { foreach (Delegate d in Comm_Send_Event.GetInvocationList()) Comm_Send_Event -= (SendRecvCallEvent)d; } } public void ClearEventRecvCall() { if (Comm_Recv_Event != null) { foreach (Delegate d in Comm_Recv_Event.GetInvocationList()) Comm_Recv_Event -= (SendRecvCallEvent)d; } } public void ServerSocketAllClearToken() { ConnectTokken.AllClearToken((ConnectTokken.Connect_Token)nSocketNumber); } public bool ServerTokenPosCheck(int iGet) { return ConnectTokken.GetTokenPosState((ConnectTokken.Connect_Token)nSocketNumber, iGet); } public void ServerSocketUnknownError(bool bCallEvent = true) { ConnectTokken.SetTokenState((ConnectTokken.Connect_Token)nSocketNumber, false); try { if (ClientSock != null) { if (ClientSock.Connected) { ClientSock.Disconnect(false); ClientSock.Shutdown(SocketShutdown.Both); ClientSock.Close(); ClientSock = null; } ClientSock = null; } //m_bOpen = false; } catch (Exception ex) { ClientSock = null; //MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Client socket release error.[SystemX.Net.Net.Comm.AsyncServerSocket] " + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG); } m_bConnected = false; if (bCallEvent) Socket_Error_Event?.Invoke(null, new ScheduleEvent(nSocketNumber, false, "Error", 0)); } private void ErrorEventProcess(Exception e, bool ConnectStateOff = false, bool bServerSock = false) { //if (e.SocketErrorCode == SocketError.NotConnected) ConnectTokken.SetTokenState((ConnectTokken.Connect_Token)nSocketNumber, false); if (bServerSock == false) m_bConnected = ConnectStateOff; else m_bOpen = ConnectStateOff; Socket_Error_Event?.Invoke(e, new ScheduleEvent(nSocketNumber, false, "Error", 0)); } private void AcceptCallback(IAsyncResult ar) { try { if (m_bOpen) { Socket SockListen = null; try { SockListen = (Socket)ar?.AsyncState; int nGetAvailable = SockListen.Available; } catch (ObjectDisposedException dispose) { SockListen = null; throw new Exception(); } if (SockListen != null) { IPEndPoint GetIPInfo = (IPEndPoint)SockListen.LocalEndPoint; if (ConnectTokken.GetTokenState((ConnectTokken.Connect_Token)nSocketNumber) == false) { ConnectTokken.SetTokenState((ConnectTokken.Connect_Token)nSocketNumber, true); //AsyncSocketObject objScoket = new AsyncSocketObject(MAXSIZE); Socket sockClient = SockListen.EndAccept(ar); //objScoket.WorkSocket = sockClient; ClientSock = sockClient; // objScoket.WorkSocket; m_bConnected = true; sockClient.BeginReceive(recvBuffer, 0, MAXSIZE, SocketFlags.None, new AsyncCallback(OnReceiveCallBack), ClientSock); Comm_Connect_Event?.BeginInvoke(ClientSock, new ScheduleEvent(nSocketNumber, true, "Connect", 0), InvokeCallback, null); } //클라이언트의 연결 요청 대기 SockListen.BeginAccept(AcceptCallback, SockListen); } } } catch (Exception e) { //종료 또는 Accept 실패. ErrorEventProcess(new CommonSocketException("Middleware server side connection lost.[SystemX.Net.Comm : AsyncServerSocket|AcceptCallback]")); } } private void InvokeCallback(object obj) { } private void SetSocketListen() { try { if (base.SOCK_TYPE == SOCKET_TYPE.TCP) { ServerSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); LingerOption SetLinger = new LingerOption(true, 0); ServerSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, SetLinger); //ServerSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); var option = new TcpKeepAlive { OnOff = 1, KeepAliveTime = 90000, KeepAliveInterval = 3000 }; int iState = ServerSock.IOControl(IOControlCode.KeepAliveValues, option.GetBytes(), null); // 서버에서 클라이언트의 연결 요청을 대기하기 위해 소켓을 열어둔다. IPEndPoint mkServerEP; mkServerEP = new IPEndPoint(SetAddress, m_iGetPort); ServerSock.Bind(mkServerEP); ServerSock.Listen(1024); SetSocketBeginReady(); } else if (base.SOCK_TYPE == SOCKET_TYPE.UDP) { ServerSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // 서버에서 클라이언트의 연결 요청을 대기하기 위해 소켓을 열어둔다. IPEndPoint mkServerEP; mkServerEP = new IPEndPoint(SetAddress, m_iGetPort); EndPoint ServerEP; ServerEP = new IPEndPoint(SetAddress, m_iGetPort); ServerSock.Bind(mkServerEP); //ServerSock.BeginReceiveFrom(recvBuffer, 0, MAXSIZE, SocketFlags.None, ref ServerEP, new AsyncCallback(OnReceiveCallBack), ServerSock); ServerSock.BeginReceive(recvBuffer, 0, MAXSIZE, SocketFlags.None, new AsyncCallback(OnReceiveCallBack), ServerSock); } m_bOpen = true; } catch (Exception e) { //종료 또는 Accept 실패. ErrorEventProcess(new CommonSocketException("Server socket open-ready fail.[SystemX.Net.Comm : AsyncServerSocket|DoInit]"), false, true); } } private void SetSocketBeginReady() { try { if (ServerSock != null) // 비동기적으로 클라이언트의 연결 요청을 받는다. ServerSock.BeginAccept(AcceptCallback, ServerSock); } catch (Exception e) { //종료 또는 Accept 실패. ErrorEventProcess(new CommonSocketException("Server socket BeginAccept() fail. [SystemX.Net.Comm : AsyncServerSocket|SetSocketListen]"), false, true); } } public override bool BeginSend(byte[] ucDatas) { bool bState = true; if (ClientSock == null) { if (base.SOCK_TYPE != SOCKET_TYPE.UDP) return false; else { if (ServerSock == null) return false; } } try { if (base.SOCK_TYPE == SOCKET_TYPE.TCP) { /* 연결 성공시 */ if (ClientSock.Connected) ClientSock.BeginSend(ucDatas, 0, ucDatas.Length, SocketFlags.None, new AsyncCallback(SendCallBack), ucDatas); } else if (base.SOCK_TYPE == SOCKET_TYPE.UDP) { if (strSetRemoteAddress.Length > 0 && strSetRemotePort.Length > 0) { EndPoint setRemote = new IPEndPoint(IPAddress.Parse(strSetRemoteAddress), int.Parse(strSetRemotePort)); ServerSock.BeginSendTo(ucDatas, 0, ucDatas.Length, SocketFlags.None, setRemote, new AsyncCallback(SendCallBack), ucDatas); } } } catch (Exception e) { bState = false; //전송 에러 ErrorEventProcess(e); } return bState; } public override bool BeginSend(Socket SetSock, byte[] ucDatas) { bool bState = true; if (SetSock == null) { if (base.SOCK_TYPE != SOCKET_TYPE.UDP) return false; else { if (ServerSock == null) return false; } } try { /* 연결 성공시 */ if (base.SOCK_TYPE == SOCKET_TYPE.TCP) { if (SetSock.Connected) SetSock.BeginSend(ucDatas, 0, ucDatas.Length, SocketFlags.None, new AsyncCallback(SendCallBack), ucDatas); } else if (base.SOCK_TYPE == SOCKET_TYPE.UDP) { if (strSetRemoteAddress.Length > 0 && strSetRemotePort.Length > 0) { EndPoint setRemote = new IPEndPoint(IPAddress.Parse(strSetRemoteAddress), int.Parse(strSetRemotePort)); ServerSock.BeginSendTo(ucDatas, 0, ucDatas.Length, SocketFlags.None, setRemote, new AsyncCallback(SendCallBack), ucDatas); } } } catch (Exception e) { bState = false; //전송 에러 ErrorEventProcess(e); } return bState; } public override bool BeginSend(string strMessage) { bool bState = true; if (ClientSock == null) { if (base.SOCK_TYPE != SOCKET_TYPE.UDP) return false; else { if (ServerSock == null) return false; } } try { byte[] buffer = new UnicodeEncoding().GetBytes(strMessage); /* 연결 성공시 */ if (base.SOCK_TYPE == SOCKET_TYPE.TCP) { if (ClientSock.Connected) ClientSock.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(SendCallBack), strMessage); } else if (base.SOCK_TYPE == SOCKET_TYPE.UDP) { if (strSetRemoteAddress.Length > 0 && strSetRemotePort.Length > 0) { EndPoint setRemote = new IPEndPoint(IPAddress.Parse(strSetRemoteAddress), int.Parse(strSetRemotePort)); ServerSock.BeginSendTo(buffer, 0, buffer.Length, SocketFlags.None, setRemote, new AsyncCallback(SendCallBack), strMessage); } } } catch (Exception e) { bState = false; //전송 에러 ErrorEventProcess(e); } return bState; } private void SendCallBack(IAsyncResult IAR) { //전송 완료 byte[] getData = null; ScheduleEvent se = new ScheduleEvent(nSocketNumber, false, "Send Fail", 0); if (ClientSock == null) { if (base.SOCK_TYPE != SOCKET_TYPE.UDP) return; else { if (ServerSock == null) return; } } bool bResult = true; try { getData = (byte[])IAR.AsyncState; if (getData != null) se = new ScheduleEvent(nSocketNumber, true, "Send Success", 0); else se = new ScheduleEvent(nSocketNumber, false, "Send Fail", 0); } catch (Exception e) { bResult = false; //Callback Error ErrorEventProcess(e); } finally { if (bResult) { Comm_Send_Event?.BeginInvoke(getData, se, null, null); } } // try { int iSendCnt = 0; if (base.SOCK_TYPE != SOCKET_TYPE.UDP) iSendCnt = ClientSock.EndSend(IAR); else iSendCnt = ServerSock.EndSend(IAR); } catch (Exception e) { bResult = false; //Callback Error ErrorEventProcess(e); } } private void Receive() { if (ClientSock == null) { if (base.SOCK_TYPE != SOCKET_TYPE.UDP) return; else { if (ServerSock == null) return; } } //받기 try { if (base.SOCK_TYPE == SOCKET_TYPE.UDP) ServerSock.BeginReceive(recvBuffer, 0, MAXSIZE, SocketFlags.None, new AsyncCallback(OnReceiveCallBack), ServerSock); else { if (ClientSock.Connected) ClientSock.BeginReceive(recvBuffer, 0, MAXSIZE, SocketFlags.None, new AsyncCallback(OnReceiveCallBack), ClientSock); } } catch (Exception e) { ErrorEventProcess(e); } } private void OnReceiveCallBack(IAsyncResult IAR) { bool bReceiveState = true; int nReadSize = 0; Socket ClientSideSock; //AsyncSocketObject objScoket = null; try { //수신 ClientSideSock = (Socket)IAR.AsyncState; //objScoket = (AsyncSocketObject)IAR.AsyncState; } catch (Exception e) { this.Dispose(); //수신 실패 ErrorEventProcess(new CommonSocketException("Middleware server side connection lost.[SystemX.Net.Comm : AsyncServerSocket|OnReceiveCallBack]")); return; } try { if (ClientSideSock.Connected) nReadSize = ClientSideSock.EndReceive(IAR); else { if (base.SOCK_TYPE == SOCKET_TYPE.UDP) nReadSize = ClientSideSock.EndReceive(IAR); else bReceiveState = false; } } catch (Exception e) { bReceiveState = false; } // if (bReceiveState) { if (nReadSize != 0) { byte[] ucFindData = new byte[1]; byte[] ucSetClearArray; int iFindDataCnt = 0; bool bDataFind = false; byte ucGetLabel = 0; try { if(bQueuePacketClearOn) { bQueuePacketClearOn = false; QPacketAllData.Clear(); } QPacketAllData.Enqueue(new CPacketDataInfo(DateTime.Now, recvBuffer, nReadSize)); foreach (var n in QPacketAllData.ToList()) { TimeSpan dsInterval = DateTime.Now - n.dtPacket; //오랜된 패킷 소거 if (dsInterval.TotalSeconds >= 20.0) QPacketAllData.Dequeue(); else QPacketRemainData.Enqueue(new CPacketDataInfo(n.ID, n.dtPacket, n.ucData, n.nDataSize)); } // iStoreCnt = 0; Array.Clear(recvStoreBuffer, 0, USER_MAX_SIZE); Guid[] guidUsePacketID = new Guid[QPacketRemainData.Count]; int nPacketPos = 0; //남은 패킷중 연산 시도 foreach (var n in QPacketRemainData.ToList()) { Array.Copy(n.ucData, 0, recvStoreBuffer, iStoreCnt, n.nDataSize); iStoreCnt += n.nDataSize; guidUsePacketID[nPacketPos++] = n.ID; for (int j = 0; j < iStoreCnt; j++) { if (recvStoreBuffer[j] == 0x0D && recvStoreBuffer[j + 1] == 0x02 && recvStoreBuffer[j + 6] == 0x08 && recvStoreBuffer[j + 7] == 0x0A) { ucGetLabel = recvStoreBuffer[j - 1]; uint uiGetPacketSize = 0x0; uiGetPacketSize |= (uint)(recvStoreBuffer[j + 2] << 24); uiGetPacketSize |= (uint)(recvStoreBuffer[j + 3] << 16); uiGetPacketSize |= (uint)(recvStoreBuffer[j + 4] << 8); uiGetPacketSize |= (uint)(recvStoreBuffer[j + 5] << 0); int iGetSize = (int)uiGetPacketSize; iGetSize += XCommons.PAD_SIZE; if (recvStoreBuffer[j + iGetSize - 4] == 0x0D && recvStoreBuffer[j + iGetSize - 3] == 0x02 && recvStoreBuffer[j + iGetSize - 2] == 0x08 && recvStoreBuffer[j + iGetSize - 1] == 0x0A) { iFindDataCnt = iGetSize; ucFindData = new byte[iFindDataCnt]; Array.Copy(recvStoreBuffer, j, ucFindData, 0, iFindDataCnt); bDataFind = true; break; } else { bDataFind = false; break; } } } // if (bDataFind) { //성공한 패킷이 있을경우 해당 패킷 제거 foreach (var m in QPacketAllData.ToList()) { for (int i = 0; i < guidUsePacketID.Count(); i++) { if (m.ID == guidUsePacketID[i]) { QPacketAllData.Dequeue(); break; } } } break; } } QPacketRemainData.Clear(); } catch (Exception e) { bDataFind = false; } // if (bDataFind) { bool bDataControl = true; byte[] ucGetInfp = null; try { ucGetInfp = new byte[iFindDataCnt]; Array.Copy(ucFindData, ucGetInfp, iFindDataCnt); } catch (Exception e) { bDataControl = false; } ScheduleEvent se = null; m_bGetRecv = true; //recvText = string.Empty; if (bDataControl) { se = new ScheduleEvent(nSocketNumber, true, "Recv Success", ucGetLabel); } else { se = new ScheduleEvent(nSocketNumber, false, "Recv Fail", ucGetLabel); } Comm_Recv_Event?.BeginInvoke(ucGetInfp, se, null, null); } this.Receive(); //objScoket.WorkSocket.BeginReceive(objScoket.recvBuffer, 0, MAXSIZE, SocketFlags.None, new AsyncCallback(OnReceiveCallBack), objScoket); } else { this.Dispose(); ErrorEventProcess(new Exception("Middleware server side connection lost.[SystemX.Net.Comm : AsyncServerSocket.OnReceiveCallBack]")); } } else { this.Dispose(); ErrorEventProcess(new Exception("Middleware server side connection lost.[SystemX.Net.Comm : AsyncServerSocket.OnReceiveCallBack]")); } } } }