Files
DDUtility/JWH/NETWORK/AsyncSocket.cs
2025-02-03 11:02:48 +09:00

973 lines
29 KiB
C#

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace JWH.NETWORK
{
/// <summary>
/// AsyncSocket
/// <para/>비동기 통신으로 개발 되었으므로, 이벤트 수신시 크로스스레드 오류가 발생할 수 있으므로 대응코드를 작성하여야 합니다.
/// </summary>
public class AsyncSocket : IDisposable
{
#region [ Events ] ====================================================
public delegate void AsyncSocketEventHandler(AsyncSocket sender, AsyncSocketEventArgs arg);
/// <summary>AsyncSocket Accept Event (Host)</summary>
public event AsyncSocketEventHandler OnAccept;
/// <summary>AsyncSocket Connect Event</summary>
public event AsyncSocketEventHandler OnConnect;
/// <summary>AsyncSocket Close Event</summary>
public event AsyncSocketEventHandler OnClose;
/// <summary>AsyncSocket Send Event</summary>
public event AsyncSocketEventHandler OnSend;
/// <summary>AsyncSocket Receive Event</summary>
public event AsyncSocketEventHandler OnReceive;
/// <summary>AsyncSocket Error Event</summary>
public event AsyncSocketEventHandler OnError;
#endregion
#region [ Variable ] ==================================================
/// <summary>Socket</summary>
private Socket m_Socket = null;
/// <summary>Host/Remote IPAddress</summary>
private string m_Address = string.Empty;
/// <summary>Port</summary>
private int m_Port = 5000;
/// <summary>Socket Name</summary>
private string m_Name = string.Empty;
#endregion
#region [ Properties ] ================================================
/// <summary>
/// Socket
/// </summary>
public Socket Socket
{
get { return this.m_Socket; }
set { this.m_Socket = value; }
}
/// <summary>
/// Host/Remote IPAddress
/// </summary>
public string Address
{
get { return this.m_Address; }
set { this.m_Address = value; }
}
/// <summary>
/// Port
/// </summary>
public int Port
{
get { return m_Port; }
set { m_Port = value; }
}
/// <summary>
/// Name
/// </summary>
public string Name
{
get { return this.m_Name; }
set { this.m_Name = value; }
}
/// <summary>
/// Host 연결상태
/// </summary>
public bool Connected
{
get { return (m_Socket == null ? false : m_Socket.Connected); }
}
#endregion
#region [ Constructors ] ==============================================
/// <summary>
/// AsyncSocket
/// </summary>
public AsyncSocket()
{
}
/// <summary>
/// AsyncSocket
/// </summary>
/// <param name="remoteAddress">Host</param>
/// <param name="port">Port</param>
public AsyncSocket(string remoteAddress, int port)
{
try
{
this.m_Address = remoteAddress;
this.m_Port = port;
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
/// <summary>
/// AsyncSocket
/// </summary>
/// <param name="socket">Socket</param>
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);
}
}
/// <summary>
/// 구성요소를 초기화합니다
/// </summary>
public void InitializeComponent()
{
try
{
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다
/// </summary>
public void Dispose()
{
try
{
if (m_Socket != null)
{
if (m_Socket.Connected == true) this.Close();
}
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
/// <summary>
/// ToString
/// </summary>
/// <returns></returns>
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;
}
}
/// <summary>
/// 지정한 개체 인스턴스가 동일한지를 확인합니다.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 기본 해시 함수로 작동합니다.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return base.GetHashCode();
}
#endregion
#region [ Methods ] ===================================================
#region [ Raise_Event ] -----------------------------------------------
/// <summary>
/// OnAccept 이벤트를 전단합니다.
/// </summary>
/// <param name="e"></param>
protected virtual void Raise_OnAccept(AsyncSocketEventArgs e)
{
try
{
this.OnAccept?.Invoke(this, e);
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
/// <summary>
/// OnConnect 이벤트를 전단합니다.
/// </summary>
/// <param name="e"></param>
protected virtual void Raise_OnConnect(AsyncSocketEventArgs e)
{
try
{
this.OnConnect?.Invoke(this, e);
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
/// <summary>
/// OnClose 이벤트를 전단합니다.
/// </summary>
/// <param name="e"></param>
protected virtual void Raise_OnClose(AsyncSocketEventArgs e)
{
try
{
this.OnClose?.Invoke(this, e);
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
/// <summary>
/// OnSend 이벤트를 전단합니다.
/// </summary>
/// <param name="e"></param>
protected virtual void Raise_OnSend(AsyncSocketEventArgs e)
{
try
{
this.OnSend?.Invoke(this, e);
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
/// <summary>
/// OnReceive 이벤트를 전단합니다.
/// </summary>
/// <param name="e"></param>
protected virtual void Raise_OnReceive(AsyncSocketEventArgs e)
{
try
{
this.OnReceive?.Invoke(this, e);
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
/// <summary>
/// OnError 이벤트를 전단합니다.
/// </summary>
/// <param name="e"></param>
protected virtual void Raise_OnError(AsyncSocketEventArgs e)
{
try
{
this.OnError?.Invoke(this, e);
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
#endregion
#region [ Connect ] ---------------------------------------------------
/// <summary>
/// Connect
/// </summary>
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);
}
}
/// <summary>
/// Connect
/// </summary>
/// <param name="hostAddress"></param>
/// <param name="port"></param>
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);
}
}
/// <summary>
/// Connect Callback
/// </summary>
/// <param name="ar"></param>
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 ] -----------------------------------------------------
/// <summary>
/// Close
/// </summary>
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);
}
}
/// <summary>
/// Close Callback
/// </summary>
/// <param name="ar"></param>
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 ] ------------------------------------------------------
/// <summary>
/// Send
/// </summary>
/// <param name="buffer"></param>
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);
}
}
/// <summary>
/// Send
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="size"></param>
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);
}
}
/// <summary>
/// Send
/// </summary>
/// <param name="buffer"></param>
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);
}
}
/// <summary>
/// Send
/// </summary>
/// <param name="buffer"></param>
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);
}
}
/// <summary>
/// Send Callback
/// </summary>
/// <param name="ar"></param>
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 ] ---------------------------------------------------
/// <summary>
/// Recive
/// </summary>
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);
}
}
/// <summary>
/// Receive Callback
/// </summary>
/// <param name="ar"></param>
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 ] ----------------------------------------------------
/// <summary>
/// Listen (Host)
/// </summary>
/// <param name="backlog">보류 중인 연결 큐의 최대 길이입니다</param>
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);
}
}
/// <summary>
/// Listen
/// </summary>
/// <param name="hostAddress">Host</param>
/// <param name="port">Port</param>
/// <param name="backlog">보류 중인 연결 큐의 최대 길이입니다</param>
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 ] ----------------------------------------------------
/// <summary>
/// Accept CallBack
/// </summary>
/// <param name="ar"></param>
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
}
/// <summary>
/// AsyncSocket Event Argument
/// </summary>
public class AsyncSocketEventArgs : EventArgs
{
#region [ Variable ] ==================================================
/// <summary>Socket</summary>
private Socket m_Socket = null;
/// <summary>Send/Receive Data</summary>
private byte[] m_Bytes = null;
/// <summary>Tag</summary>
private object m_Tag = null;
/// <summary>Exception</summary>
private Exception m_Exception = null;
#endregion
#region [ Properties ] ================================================
/// <summary>
/// Socket
/// </summary>
public Socket Socket
{
get { return this.m_Socket; }
set { this.m_Socket = value; }
}
/// <summary>
/// Send/Receive Data
/// </summary>
public byte[] Bytes
{
get { return this.m_Bytes; }
set { this.m_Bytes = value; }
}
/// <summary>
/// Exception
/// </summary>
public Exception Exception
{
get { return this.m_Exception; }
set { this.m_Exception = value; }
}
/// <summary>
/// Tag
/// </summary>
public object Tag
{
get { return this.m_Tag; }
set { this.m_Tag = value; }
}
#endregion
#region [ Constructors ] ==============================================
/// <summary>
/// 생성자
/// </summary>
public AsyncSocketEventArgs()
{
}
/// <summary>
/// 생성자
/// </summary>
/// <param name="socket">Socket</param>
public AsyncSocketEventArgs(Socket socket)
{
m_Socket = socket;
}
#endregion
}
/// <summary>
/// 비동기 작업의 상태
/// </summary>
public class AsyncObject
{
#region [ Variables ] =================================================
/// <summary>버퍼사이즈</summary>
public static int BUFFER_SIZE = 32768;
/// <summary>Socket</summary>
private Socket m_Socket;
/// <summary>Buffer</summary>
private byte[] m_byteBuffer;
#endregion
#region [ Properties ] ================================================
/// <summary>
/// Socket
/// </summary>
public Socket Socket
{
get { return this.m_Socket; }
set { this.m_Socket = value; }
}
/// <summary>
/// 버퍼
/// </summary>
public byte[] Buffer
{
get { return this.m_byteBuffer; }
set { this.m_byteBuffer = value; }
}
#endregion
#region [ Constructors ] ==============================================
/// <summary>
/// AsyncObject
/// </summary>
/// <param name="socket">Socket</param>
public AsyncObject(Socket socket)
{
try
{
this.m_Socket = socket;
this.m_byteBuffer = new byte[BUFFER_SIZE];
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
#endregion
}
}