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
}
}