본문 바로가기

C# Winform

C# Winform | AsyncSocket | Client Socket

by C기억저장소 2020. 12. 8.

C# Winform | AsyncSocket | Client Socket

 

  Socket Class 생성

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
 
namespace AsyncSocket
{
    public class StateObject
    {
        private const int BUFFER_SIZE = 327680;
 
        private Socket worker;        
        private byte[] buffer;
 
        public StateObject(Socket worker)
        {
            this.worker = worker;
            this.buffer = new byte[BUFFER_SIZE];
        }
 
        public Socket Worker
        {
            get { return this.worker; }
            set { this.worker = value; }
        }
 
        public byte[] Buffer
        {
            get { return this.buffer; }
            set { this.buffer = value; }
        }
 
        public int BufferSize
        {
            get { return BUFFER_SIZE; }
        }
    } // end of class StateObject
    
    /// <summary>
    /// 비동기 소켓에서 발생한 에러 처리를 위한 이벤트 Argument Class
    /// </summary>
    public class AsyncSocketErrorEventArgs : EventArgs
    {
        private readonly Exception exception;
        private readonly int id = 0;
 
        public AsyncSocketErrorEventArgs(int id, Exception exception )
        {
            this.id = id;
            this.exception = exception;            
        }
 
        public Exception AsyncSocketException
        {
            get { return this.exception; }
        }
 
        public int ID
        {
            get { return this.id; }
        }
    }
 
    /// <summary>
    /// 비동기 소켓의 연결 및 연결해제 이벤트 처리를 위한 Argument Class
    /// </summary>
    public class AsyncSocketConnectionEventArgs : EventArgs
    {        
        private readonly int id = 0;
 
        public AsyncSocketConnectionEventArgs(int id)
        {
            this.id = id;           
        }        
 
        public int ID
        {
            get { return this.id; }
        }
    }    
 
    /// <summary>
    /// 비동기 소캣의 데이터 전송 이벤트 처리를 위한 Argument Class
    /// </summary>
    public class AsyncSocketSendEventArgs : EventArgs
    {
        private readonly int id = 0;
        private readonly int sendBytes;        
 
        public AsyncSocketSendEventArgs(int id, int sendBytes)
        {
            this.id = id;
            this.sendBytes = sendBytes;           
        }
 
        public int SendBytes
        {
            get { return this.sendBytes; }
        }
 
        public int ID
        {
            get { return this.id; }
        }
    }    
 
    /// <summary>
    /// 비동기 소켓의 데이터 수신 이벤트 처리를 위한 Argument Class
    /// </summary>
    public class AsyncSocketReceiveEventArgs : EventArgs
    {
        private readonly int id = 0;
        private readonly int receiveBytes;
        private readonly byte[] receiveData;
 
        public AsyncSocketReceiveEventArgs(int id, int receiveBytes, byte[] receiveData)
        {
            this.id = id;
            this.receiveBytes = receiveBytes;
            this.receiveData = receiveData;
        }
 
        public int ReceiveBytes
        {
            get { return this.receiveBytes; }
        }
 
        public byte[] ReceiveData
        {
            get { return this.receiveData; }
        }
 
        public int ID
        {
            get { return this.id; }
        }
    }
 
    /// <summary>
    /// 비동기 서버의 Accept 이벤트를 위한 Argument Class
    /// </summary>
    public class AsyncSocketAcceptEventArgs : EventArgs
    {
        private readonly Socket conn;
 
        public AsyncSocketAcceptEventArgs(Socket conn)
        {
            this.conn = conn;
        }
 
        public Socket Worker
        {
            get { return this.conn; }
        }
    }    
 
    ///
    /// delegate 정의
    /// 
    public delegate void AsyncSocketErrorEventHandler(object sender, AsyncSocketErrorEventArgs e);
    public delegate void AsyncSocketConnectEventHandler(object sender, AsyncSocketConnectionEventArgs e);
    public delegate void AsyncSocketCloseEventHandler(object sender, AsyncSocketConnectionEventArgs e);
    public delegate void AsyncSocketSendEventHandler(object sender, AsyncSocketSendEventArgs e);
    public delegate void AsyncSocketReceiveEventHandler(object sender, AsyncSocketReceiveEventArgs e);
    public delegate void AsyncSocketAcceptEventHandler(object sender, AsyncSocketAcceptEventArgs e);
 
    public class AsyncSocketClass
    {
        protected int id;
 
        // Event Handler
        public event AsyncSocketErrorEventHandler OnError;
        public event AsyncSocketConnectEventHandler OnConnet;
        public event AsyncSocketCloseEventHandler OnClose;
        public event AsyncSocketSendEventHandler OnSend;
        public event AsyncSocketReceiveEventHandler OnReceive;
        public event AsyncSocketAcceptEventHandler OnAccept;
 
        public AsyncSocketClass()
        {
            this.id = -1;
        }
 
        public AsyncSocketClass(int id)
        {
            this.id = id;
        }
 
        public int ID
        {
            get { return this.id; }
        }
 
        protected virtual void ErrorOccured(AsyncSocketErrorEventArgs e)
        {
            AsyncSocketErrorEventHandler handler = OnError;
 
            if (handler != null)
                handler(this, e);
        }
 
        protected virtual void Connected(AsyncSocketConnectionEventArgs e)
        {
            AsyncSocketConnectEventHandler handler = OnConnet;
 
            if (handler != null)
                handler(this, e);
        }
 
        protected virtual void Closed(AsyncSocketConnectionEventArgs e)
        {
            AsyncSocketCloseEventHandler handler = OnClose;
 
            if (handler != null)
                handler(this, e);
        }
 
        protected virtual void Sent(AsyncSocketSendEventArgs e)
        {
            AsyncSocketSendEventHandler handler = OnSend;
 
            if (handler != null)
                handler(this, e);
        }
 
        protected virtual void Received(AsyncSocketReceiveEventArgs e)
        {
            AsyncSocketReceiveEventHandler handler = OnReceive;
 
            if (handler != null)
                handler(this, e);
        }
 
        protected virtual void Accepted(AsyncSocketAcceptEventArgs e)
        {
            AsyncSocketAcceptEventHandler handler = OnAccept;
 
            if (handler != null)
                handler(this, e);
        }
 
    } // end of class AsyncSocketClass
 
    /// <summary>
    /// 비동기 소켓
    /// </summary>
    public class AsyncSocketClient : AsyncSocketClass
    {        
        // connection socket
        private Socket conn = null;        
 
        public AsyncSocketClient(int id)
        {
            this.id = id;
        }
 
        public AsyncSocketClient(int id, Socket conn)
        {
            this.id = id;
            this.conn = conn;            
        }
 
        public Socket Connection
        {
            get { return this.conn; }
            set { this.conn = value; }
        }
 
        /// <summary>
        /// 연결을 시도한다.
        /// </summary>
        /// <param name="hostAddress"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public bool Connect(string hostAddress, int port)
        {
            try
            {
                IPAddress[] ips = Dns.GetHostAddresses(hostAddress);
                IPEndPoint remoteEP = new IPEndPoint(ips[0], port);
                Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 
                client.BeginConnect(remoteEP, new AsyncCallback(OnConnectCallback), client);
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);
 
                return false;
            }
 
            return true;
            
        }
 
        /// <summary>
        /// 연결 요청 처리 콜백 함수
        /// </summary>
        /// <param name="ar"></param>
        private void OnConnectCallback(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
 
                // 보류 중인 연결을 완성한다.
                client.EndConnect(ar);
 
                conn = client;
                conn.NoDelay = true;
 
                // 연결에 성공하였다면, 데이터 수신을 대기한다.
                Receive();
 
                // 연결 성공 이벤트를 날린다.
                AsyncSocketConnectionEventArgs cev = new AsyncSocketConnectionEventArgs(this.id);
                Connected(cev);
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);
            }
        }
 
        /// <summary>
        /// 데이터 수신을 비동기적으로 처리
        /// </summary>
        public void Receive()
        {
            try
            {
                StateObject so = new StateObject(conn);
 
                so.Worker.BeginReceive(so.Buffer, 0, so.BufferSize, 0new AsyncCallback(OnReceiveCallBack), so);
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);
            }
        }
 
        /// <summary>
        /// 데이터 수신 처리 콜백 함수
        /// </summary>
        /// <param name="ar"></param>
        private void OnReceiveCallBack(IAsyncResult ar)
        {
            try
            {
                StateObject so = (StateObject)ar.AsyncState;
 
                int bytesRead = so.Worker.EndReceive(ar);
 
                AsyncSocketReceiveEventArgs rev = new AsyncSocketReceiveEventArgs(this.id, bytesRead, so.Buffer);
 
                // 데이터 수신 이벤트를 처리한다.
                if(bytesRead > 0)
                    Received(rev);
 
                // 다음 읽을 데이터를 처리한다.
                Receive();
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);
            }
        }
 
        /// <summary>
        /// 데이터 송신을 비동기적으로 처리
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public bool Send(byte[] buffer)
        {
            try
            {
                Socket client = conn;
 
                client.BeginSend(buffer, 0, buffer.Length, 0new AsyncCallback(OnSendCallBack), client);
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);
 
                return false;
            }
 
            return true;
        }
 
        /// <summary>
        /// 데이터 송신 처리 콜백 함수
        /// </summary>
        /// <param name="ar"></param>
        private void OnSendCallBack(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
 
                int bytesWritten = client.EndSend(ar);
 
                AsyncSocketSendEventArgs sev = new AsyncSocketSendEventArgs(this.id, bytesWritten);
 
                Sent(sev);
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);
            }
        }
 
        /// <summary>
        /// 소켓 연결을 비동기적으로 종료
        /// </summary>
        public void Close()
        {
            try
            {
                Socket client = conn;
 
                client.Shutdown(SocketShutdown.Both);
                client.BeginDisconnect(falsenew AsyncCallback(OnCloseCallBack), client);
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);
            }
        }
 
        /// <summary>
        /// 소켓 연결 종료를 처리하는 콜백 함수
        /// </summary>
        /// <param name="ar"></param>
        private void OnCloseCallBack(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
 
                client.EndDisconnect(ar);
                client.Close();                
 
                AsyncSocketConnectionEventArgs cev = new AsyncSocketConnectionEventArgs(this.id);
 
                Closed(cev);
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);
            }
        }        
 
    } // end of class AsyncSocketClient
 
    /// <summary>
    /// 비동기 방식의 서버 
    /// </summary>
    public class AsyncSocketServer : AsyncSocketClass
    {
        private const int backLog = 100;        
 
        private int port;                
        private Socket listener;        
 
        public AsyncSocketServer(int port)
        {
            this.port = port;            
        }
 
        public int Port
        {
            get { return this.port; }
        }      
 
        public void Listen()
        {
            try
            {
                listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);                                
                listener.Bind(new IPEndPoint(IPAddress.Any, this.port));
                listener.Listen(backLog);
 
                StartAccept();
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);
            }    
        }
 
        /// <summary>
        /// Client의 접속을 비동기적으로 대기한다.
        /// </summary>
        /// <returns></returns>
        private void StartAccept()
        {
            try
            {
                listener.BeginAccept(new AsyncCallback(OnListenCallBack), listener);            
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);
            }                                    
        }
 
        /// <summary>
        /// Client의 비동기 접속을 처리한다.
        /// </summary>
        /// <param name="ar"></param>
        private void OnListenCallBack(IAsyncResult ar)
         {
            try
            {
                Socket listener = (Socket)ar.AsyncState;
                Socket worker = listener.EndAccept(ar);
                
                // Client를 Accept 했다고 Event를 발생시킨다.
                AsyncSocketAcceptEventArgs aev = new AsyncSocketAcceptEventArgs(worker);
 
                Accepted(aev);
 
                // 다시 새로운 클라이언트의 접속을 기다린다.
                StartAccept();
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);
            }
        }
 
        public void Stop()
        {
            try
            {
                if(listener != null)
                {
                    if (listener.IsBound)
                        listener.Close(100);
                }
            }
            catch (System.Exception e)
            {
                AsyncSocketErrorEventArgs eev = new AsyncSocketErrorEventArgs(this.id, e);
 
                ErrorOccured(eev);   
            }
        }
 
    } // end of class AsyncSocketServer
 
// end of namespace
 
cs
클래스 이름 : AsyncSocket.cs

 

 

 

  Socket 사용법

 

1. using 설정

 

using AsyncSocket;
cs

 

2. Socket 선언 및 초기화

 

private AsyncSocketClient Socket;
 
public AsyncSocketTest() //생성자
{
    InitializeComponent();
 
    Socket = new AsyncSocketClient(0);
    Socket.OnConnet += new AsyncSocketConnectEventHandler(OnConnet);
    Socket.OnClose += new AsyncSocketCloseEventHandler(OnClose);
    Socket.OnSend += new AsyncSocketSendEventHandler(OnSend);
    Socket.OnReceive += new AsyncSocketReceiveEventHandler(OnReceive);
    Socket.OnError += new AsyncSocketErrorEventHandler(OnError);
}
cs

 

3. Event 함수

 

private void OnConnet(object sender, AsyncSocketConnectionEventArgs e)
{
    Console.WriteLine("Socket OnConnet");
}
 
private void OnClose(object sender, AsyncSocketConnectionEventArgs e)
{
    Console.WriteLine("Socket OnClose");
}
 
private void OnSend(object sender, AsyncSocketSendEventArgs e)
{
    Console.WriteLine("Socket OnSend");
}
        
private void OnReceive(object sender, AsyncSocketReceiveEventArgs e)
{
    byte[] tbuf = new byte[e.ReceiveBytes];
    e.ReceiveData.Take(e.ReceiveBytes).ToArray().CopyTo(tbuf, 0);
}
 
private void OnError(object sender, AsyncSocketErrorEventArgs e)
{
    Console.WriteLine("Socket OnError");
}
cs

 

4. Connect / Close / Send

 

private void btnConnect_Click(object sender, EventArgs e)
{
    Socket.Connect("127.0.0.1"1544);
}
 
private void btnClose_Click(object sender, EventArgs e)
{
    Socket.Close();
}
 
private void btnSend_Click(object sender, EventArgs e)
{
    byte[] sendData = Encoding.UTF8.GetBytes("SendData");
    Socket.Send(sendData);
}
cs

 

 

 

  Test Code

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using AsyncSocket;
 
namespace Test
{
    public partial class AsyncSocketTest : Form
    {
        private AsyncSocketClient Socket;
 
        public AsyncSocketTest()
        {
            InitializeComponent();
 
            Socket = new AsyncSocketClient(0);
            Socket.OnConnet += new AsyncSocketConnectEventHandler(OnConnet);
            Socket.OnClose += new AsyncSocketCloseEventHandler(OnClose);
            Socket.OnSend += new AsyncSocketSendEventHandler(OnSend);
            Socket.OnReceive += new AsyncSocketReceiveEventHandler(OnReceive);
            Socket.OnError += new AsyncSocketErrorEventHandler(OnError);
        }
 
        private void AsyncSocketTest_Load(object sender, EventArgs e)
        {
 
        }
 
        private void OnConnet(object sender, AsyncSocketConnectionEventArgs e)
        {
            Console.WriteLine("Socket OnConnet");
        }
        private void OnClose(object sender, AsyncSocketConnectionEventArgs e)
        {
            Console.WriteLine("Socket OnClose");
        }
        private void OnSend(object sender, AsyncSocketSendEventArgs e)
        {
            Console.WriteLine("Socket OnSend");
        }
        private void OnReceive(object sender, AsyncSocketReceiveEventArgs e)
        {
            byte[] tbuf = new byte[e.ReceiveBytes];
            e.ReceiveData.Take(e.ReceiveBytes).ToArray().CopyTo(tbuf, 0);
        }
 
        private void OnError(object sender, AsyncSocketErrorEventArgs e)
        {
            Console.WriteLine("Socket OnError");
        }
 
        private void btnConnect_Click(object sender, EventArgs e)
        {
            Socket.Connect("127.0.0.1"1544);
        }
 
        private void btnClose_Click(object sender, EventArgs e)
        {
            Socket.Close();
        }
    }
}
 
cs

 

 

 

  Result