using System; using System.Collections.Concurrent; 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; namespace SystemX.Net.Comm { public class AsyncComClientSocket : SystemXSocket, IDisposable { 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_bConnected; private string m_strGetText; private bool m_bGetRecv; private bool bDisposed; 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; public override event EventHandler AwaitSendEvent; public override event EventHandler AwaitRecvEvent; private Queue QPacketAllData; private Queue QPacketRemainData; private bool bQueuePacketClearOn; public override void SetRefSocketPacketClear() { bQueuePacketClearOn = true; } /* private Task taskSendQueue; private bool m_bThreadSendBlock; private ConcurrentQueue qSendData = new ConcurrentQueue(); AutoResetEvent stopWaitHandle = new AutoResetEvent(false); */ public bool 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 strGetLocalAddress { set; get; } public string strGetLocalPort { set; get; } public AsyncComClientSocket(SOCKET_TYPE SOCK_TYPE, IPEndPoint SetRemote) : base(SOCKET_RULE.CLIENT, SOCK_TYPE) { nSocketNumber = 100; bDisposed = false; QPacketAllData = new Queue(); QPacketRemainData = new Queue(); bQueuePacketClearOn = false; m_strGetIp = SetRemote.Address.ToString(); m_iGetPort = SetRemote.Port; 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_bConnected = false; AwaitSendEvent += SendCompleteEvent; /* taskSendQueue = null; m_bThreadSendBlock = false; taskSendQueue = new Task(new Action(WatchSendQueue)); taskSendQueue.Start(); */ this.DoInit(); } private async void WatchSendQueue() { /* while (!m_bThreadSendBlock) { try { if(qSendData.Count > 0) { byte[] ucGetData; if(qSendData.TryDequeue(out ucGetData)) { cbClientSock.BeginSend(ucGetData, 0, ucGetData.Length, SocketFlags.None, new AsyncCallback(SendCallBack), ucGetData); stopWaitHandle.WaitOne(); } } } catch (Exception e) { ErrorEventProcess(new CommonSocketException("Send error.[SystemX.Net.Comm : AsyncClientSocket|WatchSendQueue]")); } await Task.Delay(1); } */ await Task.Delay(1); } 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 ClearEventAsyncSendCall() { if (AwaitSendEvent != null) { foreach (Delegate d in AwaitSendEvent.GetInvocationList()) AwaitSendEvent -= (EventHandler)d; } } public void ClearEventAsyncRecvCall() { if (AwaitRecvEvent != null) { foreach (Delegate d in AwaitRecvEvent.GetInvocationList()) AwaitRecvEvent -= (EventHandler)d; } } protected override void Dispose(bool disposing) { if (!bDisposed) { AwaitSendEvent -= SendCompleteEvent; try { /* if (taskSendQueue != null) { m_bThreadSendBlock = true; taskSendQueue.Wait(); } */ // dispose managed resource (종결자를 가진 객체의 자원 해제) /* if (cbClientSock != null) { if (cbClientSock.Connected) { cbClientSock.Disconnect(false); cbClientSock.Shutdown(SocketShutdown.Both); cbClientSock.Close(); cbClientSock = null; } cbClientSock = null; } */ if (ClientSock != null) { if (ClientSock.Connected) { ClientSock.Disconnect(false); ClientSock.Shutdown(SocketShutdown.Both); ClientSock.Close(); ClientSock = null; } ClientSock = null; } /*if(cbClientSock != null) cbClientSock.Close();*/ cbClientSock = null; m_bConnected = false; } catch { cbClientSock = null; ClientSock = null; m_bConnected = false; ErrorEventProcess(new Exception("Dispose failed. [SystemX.Net.Comm : AsyncComClientSocket.Dispose]")); } finally { ClearEventAsyncSendCall(); ClearEventAsyncRecvCall(); ClearEventSendCall(); ClearEventRecvCall(); /* ClearEventConnectCall(); ClearEventErrorCall(); */ } if (disposing) { //Manage } //Unmanage recvStoreBuffer = null; recvBuffer = null; bDisposed = true; } //Base Dispose base.Dispose(disposing); } private void ErrorEventProcess(Exception e, bool ConnectStateOff = false) { //if (e.SocketErrorCode == SocketError.NotConnected) m_bConnected = ConnectStateOff; Socket_Error_Event?.Invoke(e, new ScheduleEvent(nSocketNumber, false, "Error", 0)); } private void DoInit() { bool bDoState = true; try { if (base.SOCK_TYPE == SOCKET_TYPE.TCP) ClientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); else if (base.SOCK_TYPE == SOCKET_TYPE.UDP) ClientSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); if (base.SOCK_TYPE == SOCKET_TYPE.TCP) { LingerOption SetLinger = new LingerOption(true, 1); ClientSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, SetLinger); //ClientSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); var option = new TcpKeepAlive { OnOff = 1, KeepAliveTime = 90000, KeepAliveInterval = 3000 }; int iState = ClientSock.IOControl(IOControlCode.KeepAliveValues, option.GetBytes(), null); } } catch (Exception e) { bDoState = false; /* 접속 실패 */ ErrorEventProcess(e); } finally { if (bDoState) this.BeginConnect(); } } private void BeginConnect() { try { /* 접속 대기중 */ ClientSock.BeginConnect(m_strGetIp, m_iGetPort, new AsyncCallback(ConnectCallBack), ClientSock); } catch (Exception e) { /* 접속 실패 */ ErrorEventProcess(e); } } private void ConnectCallBack(IAsyncResult IAR) { try { //보류중인 연결을 완성 Socket tempSock = (Socket)IAR.AsyncState; IPEndPoint svrEP = (IPEndPoint)tempSock.RemoteEndPoint; IPEndPoint connEP = (IPEndPoint)tempSock.LocalEndPoint; string strLocalAddress = connEP.Address.ToString(); string strLocalPort = connEP.Port.ToString(); strGetLocalAddress = strLocalAddress; strGetLocalPort = strLocalPort; tempSock.EndConnect(IAR); //AsyncSocketObject objScoket = new AsyncSocketObject(MAXSIZE); //objScoket.WorkSocket = tempSock; cbClientSock = tempSock; /* LingerOption SetLinger = new LingerOption(true, 1); cbClientSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, SetLinger); cbClientSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); var option = new TcpKeepAlive { OnOff = 1, KeepAliveTime = 53000, KeepAliveInterval = 2000 }; int iState = cbClientSock.IOControl(IOControlCode.KeepAliveValues, option.GetBytes(), null); */ //데이터 받을 이벤트 함수 등록 cbClientSock.BeginReceive(recvBuffer, 0, MAXSIZE, SocketFlags.None, new AsyncCallback(OnReceiveCallBack), ClientSock); m_bConnected = true; Comm_Connect_Event?.BeginInvoke(ClientSock, new ScheduleEvent(nSocketNumber, true, "Connect", 0), InvokeCallback, null); } catch (Exception e) { /* 접속 실패 */ ErrorEventProcess(e); } } private void InvokeCallback(object obj) { } public override bool BeginSend(byte[] ucDatas) { bool bState = true; if (cbClientSock == null) return false; //qSendData.Enqueue(ucDatas); try { //연결 성공시 if (cbClientSock.Connected || base.SOCK_TYPE == SOCKET_TYPE.UDP) { cbClientSock.BeginSend(ucDatas, 0, ucDatas.Length, SocketFlags.None, 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 (cbClientSock == null) return false; try { //연결 성공시 if (SetSock.Connected || base.SOCK_TYPE == SOCKET_TYPE.UDP) { SetSock.BeginSend(ucDatas, 0, ucDatas.Length, SocketFlags.None, new AsyncCallback(SendCallBack), ucDatas); } } catch (Exception e) { bState = false; //전송 에러 ErrorEventProcess(e); } return bState; } public override bool BeginSend(string strMessage) { bool bState = true; if (cbClientSock == null) return false; try { //연결 성공시 if (cbClientSock.Connected || base.SOCK_TYPE == SOCKET_TYPE.UDP) { byte[] buffer = new UnicodeEncoding().GetBytes(strMessage); cbClientSock.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, 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 (cbClientSock == 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); AwaitSendEvent?.BeginInvoke(getData, se, null, null); //Comm_Send_Event?.Invoke(getData, se); //AwaitSendEvent?.Invoke(getData, se); } } try { int iSendCnt = cbClientSock.EndSend(IAR); } catch (Exception e) { bResult = false; //Callback Error ErrorEventProcess(e); } } private void SendCompleteEvent(object senderData, ScheduleEvent e) { } private void Receive() { if (cbClientSock == null) return; //받기 try { if (cbClientSock.Connected || base.SOCK_TYPE == SOCKET_TYPE.UDP) cbClientSock.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 = null; //AsyncSocketObject objScoket = null; try { //수신 ClientSideSock = (Socket)IAR.AsyncState; //objScoket = (AsyncSocketObject)IAR.AsyncState; } catch (Exception e) { this.Dispose(true); //수신 실패 ErrorEventProcess(new CommonSocketException("Middleware server side connection lost.[SystemX.Net.Comm : AsyncClientSocket|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]; 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); AwaitRecvEvent?.BeginInvoke(ucGetInfp, se, null, null); //Comm_Recv_Event?.Invoke(ucGetInfp, se); //AwaitRecvEvent?.Invoke(ucGetInfp, se); } this.Receive(); //objScoket.WorkSocket.BeginReceive(objScoket.recvBuffer, 0, MAXSIZE, SocketFlags.None, new AsyncCallback(OnReceiveCallBack), objScoket); } else { this.Dispose(true); ErrorEventProcess(new CommonSocketException("Middleware server side connection lost.[SystemX.Net.Comm : AsyncClientSocket|OnReceiveCallBack]")); } } else { this.Dispose(true); ErrorEventProcess(new CommonSocketException("Middleware server side connection lost.[SystemX.Net.Comm : AsyncClientSocket|OnReceiveCallBack]")); } } } }