using System; using System.Net; using System.Net.Sockets; using System.Text; namespace JWH.NETWORK { /// /// AsyncSocket /// 비동기 통신으로 개발 되었으므로, 이벤트 수신시 크로스스레드 오류가 발생할 수 있으므로 대응코드를 작성하여야 합니다. /// public class AsyncSocket : IDisposable { #region [ Events ] ==================================================== public delegate void AsyncSocketEventHandler(AsyncSocket sender, AsyncSocketEventArgs arg); /// AsyncSocket Accept Event (Host) public event AsyncSocketEventHandler OnAccept; /// AsyncSocket Connect Event public event AsyncSocketEventHandler OnConnect; /// AsyncSocket Close Event public event AsyncSocketEventHandler OnClose; /// AsyncSocket Send Event public event AsyncSocketEventHandler OnSend; /// AsyncSocket Receive Event public event AsyncSocketEventHandler OnReceive; /// AsyncSocket Error Event public event AsyncSocketEventHandler OnError; #endregion #region [ Variable ] ================================================== /// Socket private Socket m_Socket = null; /// Host/Remote IPAddress private string m_Address = string.Empty; /// Port private int m_Port = 5000; /// Socket Name private string m_Name = string.Empty; #endregion #region [ Properties ] ================================================ /// /// Socket /// public Socket Socket { get { return this.m_Socket; } set { this.m_Socket = value; } } /// /// Host/Remote IPAddress /// public string Address { get { return this.m_Address; } set { this.m_Address = value; } } /// /// Port /// public int Port { get { return m_Port; } set { m_Port = value; } } /// /// Name /// public string Name { get { return this.m_Name; } set { this.m_Name = value; } } /// /// Host 연결상태 /// public bool Connected { get { return (m_Socket == null ? false : m_Socket.Connected); } } #endregion #region [ Constructors ] ============================================== /// /// AsyncSocket /// public AsyncSocket() { } /// /// AsyncSocket /// /// Host /// Port public AsyncSocket(string remoteAddress, int port) { try { this.m_Address = remoteAddress; this.m_Port = port; } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } /// /// AsyncSocket /// /// Socket public AsyncSocket(Socket socket) { try { this.m_Socket = socket; try { IPEndPoint endpoint = (IPEndPoint)this.m_Socket.RemoteEndPoint; this.m_Address = endpoint.Address.ToString(); this.m_Port = endpoint.Port; } catch { IPEndPoint endpoint = (IPEndPoint)this.m_Socket.LocalEndPoint; this.m_Address = endpoint.Address.ToString(); this.m_Port = endpoint.Port; } if (this.m_Socket != null && this.m_Socket.IsBound) { this.Receive(); } } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } /// /// 구성요소를 초기화합니다 /// public void InitializeComponent() { try { } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } /// /// 사용 중인 모든 리소스를 정리합니다 /// public void Dispose() { try { if (m_Socket != null) { if (m_Socket.Connected == true) this.Close(); } } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } /// /// ToString /// /// public override string ToString() { try { if (this.m_Socket == null) return this.Name; string strValue = string.Empty; try { strValue = string.Format("{0}:{1}", this.m_Socket.RemoteEndPoint.ToString(), this.Name); } catch { try { strValue = string.Format("{0}:{1}", this.m_Socket.LocalEndPoint.ToString(), this.Name); } catch { } } return strValue; } catch { return this.Name; } } /// /// 지정한 개체 인스턴스가 동일한지를 확인합니다. /// /// /// public override bool Equals(object obj) { if (obj == null) return false; AsyncSocket temp = obj as AsyncSocket; if (temp == null) return false; if (temp.Name != this.Name) return false; if (temp.m_Address != this.Address) return false; if (temp.Port != this.Port) return false; if (temp.Socket != this.Socket) return false; return true; } /// /// 기본 해시 함수로 작동합니다. /// /// public override int GetHashCode() { return base.GetHashCode(); } #endregion #region [ Methods ] =================================================== #region [ Raise_Event ] ----------------------------------------------- /// /// OnAccept 이벤트를 전단합니다. /// /// protected virtual void Raise_OnAccept(AsyncSocketEventArgs e) { try { this.OnAccept?.Invoke(this, e); } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } /// /// OnConnect 이벤트를 전단합니다. /// /// protected virtual void Raise_OnConnect(AsyncSocketEventArgs e) { try { this.OnConnect?.Invoke(this, e); } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } /// /// OnClose 이벤트를 전단합니다. /// /// protected virtual void Raise_OnClose(AsyncSocketEventArgs e) { try { this.OnClose?.Invoke(this, e); } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } /// /// OnSend 이벤트를 전단합니다. /// /// protected virtual void Raise_OnSend(AsyncSocketEventArgs e) { try { this.OnSend?.Invoke(this, e); } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } /// /// OnReceive 이벤트를 전단합니다. /// /// protected virtual void Raise_OnReceive(AsyncSocketEventArgs e) { try { this.OnReceive?.Invoke(this, e); } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } /// /// OnError 이벤트를 전단합니다. /// /// protected virtual void Raise_OnError(AsyncSocketEventArgs e) { try { this.OnError?.Invoke(this, e); } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } #endregion #region [ Connect ] --------------------------------------------------- /// /// Connect /// public void Connect() { try { if (this.m_Socket != null && this.m_Socket.Connected == true) return; IPAddress[] ipAddress = Dns.GetHostAddresses(this.m_Address); IPEndPoint ipEndPoint = new IPEndPoint(ipAddress[0], m_Port); if (this.m_Socket == null) { this.m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); this.m_Socket.ReceiveBufferSize = AsyncObject.BUFFER_SIZE; } this.m_Socket.BeginConnect(ipEndPoint, new AsyncCallback(this.OnConnectCallback), this.m_Socket); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(); arg.Exception = exa; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(); arg.Exception = ex; this.Raise_OnError(arg); } } /// /// Connect /// /// /// public void Connect(string hostAddress, int port) { try { if (this.m_Socket != null && this.m_Socket.Connected == true) return; this.m_Address = hostAddress; this.m_Port = port; this.Connect(); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; this.Raise_OnError(arg); } } /// /// Connect Callback /// /// protected void OnConnectCallback(IAsyncResult ar) { try { Socket client = (Socket)ar.AsyncState; client.EndConnect(ar); // OnConnect 이벤트를 날린다. AsyncSocketEventArgs arg = new AsyncSocketEventArgs(client); this.Raise_OnConnect(arg); this.Receive(); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; this.Raise_OnError(arg); } } #endregion #region [ Close ] ----------------------------------------------------- /// /// Close /// public void Close() { try { if (this.m_Socket.Connected == true) { this.m_Socket.Shutdown(SocketShutdown.Both); this.m_Socket.BeginDisconnect(false, new AsyncCallback(OnCloseCallback), this.m_Socket); } else { this.m_Socket.Close(100); this.m_Socket = null; } } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; this.Raise_OnError(arg); } } /// /// Close Callback /// /// protected void OnCloseCallback(IAsyncResult ar) { try { Socket client = (Socket)ar.AsyncState; // OnClose 이벤트를 전송한다 AsyncSocketEventArgs arg = new AsyncSocketEventArgs(client); this.Raise_OnClose(arg); if (client.IsBound) { client.EndDisconnect(ar); client.Close(); } } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; this.Raise_OnError(arg); } } #endregion #region [ Send ] ------------------------------------------------------ /// /// Send /// /// public void Send(byte[] buffer, object tag = null) { try { this.m_Socket.BeginSend(buffer, 0, buffer.Length, 0, new AsyncCallback(OnSendCallback), this.m_Socket); AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Bytes = buffer; arg.Tag = tag; this.Raise_OnSend(arg); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; arg.Tag = tag; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; arg.Tag = tag; this.Raise_OnError(arg); } } /// /// Send /// /// /// /// public void Send(byte[] buffer, int offset, int size, object tag = null) { try { this.m_Socket.BeginSend(buffer, offset, size, 0, new AsyncCallback(OnSendCallback), this.m_Socket); AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Bytes = buffer.Clone(offset, size); arg.Tag = tag; this.Raise_OnSend(arg); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; arg.Tag = tag; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; arg.Tag = tag; this.Raise_OnError(arg); } } /// /// Send /// /// public void Send(string buffer, object tag = null) { try { byte[] byteBuffer = Encoding.ASCII.GetBytes(buffer); this.m_Socket.BeginSend(byteBuffer, 0, buffer.Length, 0, new AsyncCallback(this.OnSendCallback), this.m_Socket); AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Bytes = byteBuffer; arg.Tag = tag; this.Raise_OnSend(arg); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; arg.Tag = tag; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; arg.Tag = tag; this.Raise_OnError(arg); } } /// /// Send /// /// public void Send(string buffer, Encoding encoding, object tag = null) { try { byte[] byteBuffer = encoding.GetBytes(buffer); this.m_Socket.BeginSend(byteBuffer, 0, buffer.Length, 0, new AsyncCallback(this.OnSendCallback), this.m_Socket); AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Bytes = byteBuffer; arg.Tag = tag; this.Raise_OnSend(arg); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; arg.Tag = tag; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; arg.Tag = tag; this.Raise_OnError(arg); } } /// /// Send Callback /// /// protected void OnSendCallback(IAsyncResult ar) { try { Socket client = (Socket)ar.AsyncState; int bytesWritten = client.EndSend(ar); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; this.Raise_OnError(arg); } } #endregion #region [ Receive ] --------------------------------------------------- /// /// Recive /// public void Receive() { try { AsyncObject stateObject = new AsyncObject(this.m_Socket); this.m_Socket.BeginReceive(stateObject.Buffer, 0, AsyncObject.BUFFER_SIZE, 0, new AsyncCallback(this.OnReceiveCallback), stateObject); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(); arg.Exception = exa; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(); arg.Exception = ex; this.Raise_OnError(arg); } } /// /// Receive Callback /// /// protected void OnReceiveCallback(IAsyncResult ar) { try { AsyncObject stateObject = ar.AsyncState as AsyncObject; Socket client = stateObject.Socket; int nLength = client.EndReceive(ar); if (nLength == 0) { this.Close(); return; } // OnReceive 이벤트를 전송한다 AsyncSocketEventArgs arg = new AsyncSocketEventArgs(client); arg.Bytes = stateObject.Buffer.Clone(0, nLength); this.Raise_OnReceive(arg); this.Receive(); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; this.Raise_OnError(arg); } } #endregion #region [ Listen ] ---------------------------------------------------- /// /// Listen (Host) /// /// 보류 중인 연결 큐의 최대 길이입니다 public void Listen(int backlog = 100) { try { IPAddress[] ipAddress = Dns.GetHostAddresses(m_Address); IPEndPoint ipEndPoint = new IPEndPoint(ipAddress[0], m_Port); if (this.m_Socket == null) { this.m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); this.m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); } this.m_Socket.Bind(ipEndPoint); this.m_Socket.Listen(backlog); this.m_Socket.BeginAccept(new AsyncCallback(this.OnAcceptCallback), this.m_Socket); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; this.Raise_OnError(arg); } } /// /// Listen /// /// Host /// Port /// 보류 중인 연결 큐의 최대 길이입니다 public void Listen(string hostAddress, int port, int backlog = 100) { try { this.m_Address = hostAddress; this.m_Port = port; this.Listen(backlog); } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } #endregion #region [ Accept ] ---------------------------------------------------- /// /// Accept CallBack /// /// protected void OnAcceptCallback(IAsyncResult ar) { try { if (this.m_Socket == null) return; Socket listener = (Socket)ar.AsyncState; if (!listener.IsBound) return; Socket client = listener.EndAccept(ar); AsyncSocketEventArgs arg = new AsyncSocketEventArgs(client); this.Raise_OnAccept(arg); this.m_Socket.BeginAccept(new AsyncCallback(this.OnAcceptCallback), this.m_Socket); } catch (SocketException exa) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = exa; this.Raise_OnError(arg); } catch (Exception ex) { AsyncSocketEventArgs arg = new AsyncSocketEventArgs(this.m_Socket); arg.Exception = ex; this.Raise_OnError(arg); } } #endregion #endregion } /// /// AsyncSocket Event Argument /// public class AsyncSocketEventArgs : EventArgs { #region [ Variable ] ================================================== /// Socket private Socket m_Socket = null; /// Send/Receive Data private byte[] m_Bytes = null; /// Tag private object m_Tag = null; /// Exception private Exception m_Exception = null; #endregion #region [ Properties ] ================================================ /// /// Socket /// public Socket Socket { get { return this.m_Socket; } set { this.m_Socket = value; } } /// /// Send/Receive Data /// public byte[] Bytes { get { return this.m_Bytes; } set { this.m_Bytes = value; } } /// /// Exception /// public Exception Exception { get { return this.m_Exception; } set { this.m_Exception = value; } } /// /// Tag /// public object Tag { get { return this.m_Tag; } set { this.m_Tag = value; } } #endregion #region [ Constructors ] ============================================== /// /// 생성자 /// public AsyncSocketEventArgs() { } /// /// 생성자 /// /// Socket public AsyncSocketEventArgs(Socket socket) { m_Socket = socket; } #endregion } /// /// 비동기 작업의 상태 /// public class AsyncObject { #region [ Variables ] ================================================= /// 버퍼사이즈 public static int BUFFER_SIZE = 32768; /// Socket private Socket m_Socket; /// Buffer private byte[] m_byteBuffer; #endregion #region [ Properties ] ================================================ /// /// Socket /// public Socket Socket { get { return this.m_Socket; } set { this.m_Socket = value; } } /// /// 버퍼 /// public byte[] Buffer { get { return this.m_byteBuffer; } set { this.m_byteBuffer = value; } } #endregion #region [ Constructors ] ============================================== /// /// AsyncObject /// /// Socket public AsyncObject(Socket socket) { try { this.m_Socket = socket; this.m_byteBuffer = new byte[BUFFER_SIZE]; } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } #endregion } }