TCP통신

비동기 Socket Server (1:1)

2021. 12. 23. 20:49

심플해보이지만 잘 작동하는 소스

// Author: CodeReaper
// Last update: 2022/01/01

using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncSocket
{
    /// <summary>
    /// 핸들링할 객체를 담아둘 Class
    /// </summary>
    public class StateObject
    {
        // Size of receive buffer.  
        public const int BufferSize = 1024;
        // Receive buffer.  
        public byte[] buffer = new byte[BufferSize];
        // Received data string.
        public StringBuilder sb = new StringBuilder();
        // Client socket.
        public Socket workSocket = null;
    }

    /// <summary>
    /// 비동기 소켓 서버
    /// </summary>
    public class Server
    {
        public int LocalPort { get; set; } = 0;

        //연결 event
        public event onConnectEventHandler onConnect;
        public delegate void onConnectEventHandler(object sender, string remoteIP, string remotePort);

        //연결해제 event
        public event onDisconnectEventHandler onDisconnect;
        public delegate void onDisconnectEventHandler(object sender);

        //수신 event
        public event onDataArrivalEventHandler onDataArrival;
        public delegate void onDataArrivalEventHandler(object sender, byte[] Data, int bytesRead);

        //송신 event
        public event onSendCompleteEventHandler onSendComplete;
        public delegate void onSendCompleteEventHandler(object sender, byte[] Data);

        public Server(int ListenPort = 0)
        {
            LocalPort = ListenPort;
        }

        protected StateObject _state = null;
        Socket listener;

        public async void Listen()
        {
            if (_state != null)
            {
                return;
            }

            if (LocalPort < 1)
            {
                return;
            }

            IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
            IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, LocalPort);

            // Create a TCP/IP socket.  
            listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // Bind the socket to the local endpoint and listen for incoming connections.  
            try
            {
                listener.Bind(localEndPoint);
                listener.Listen(10);

                while (true)
                {
                    Socket clientSock = await Task.Factory.FromAsync(listener.BeginAccept, listener.EndAccept, null);

                    onConnect?.Invoke(this, ((IPEndPoint)clientSock.RemoteEndPoint).Address.ToString(), ((IPEndPoint)clientSock.RemoteEndPoint).Port.ToString());
                    // Create the state object.  
                    _state = new StateObject();
                    _state.workSocket = clientSock;
                    clientSock.BeginReceive(_state.buffer, 0, StateObject.BufferSize, 0,
                        new AsyncCallback(ReadCallback), _state);
                }
            }
            catch
            {
                Stop();
            }
            finally
            {
            }

        }

        private void ReadCallback(IAsyncResult ar)
        {
            try
            {
                _state = (StateObject)ar.AsyncState;
                Socket handler = _state.workSocket;

                // Read data from the client socket.
                int bytesRead = handler.EndReceive(ar);

                if (bytesRead > 0)
                {
                    byte[] rcvBuff = new byte[bytesRead];
                    Array.Copy(_state.buffer, rcvBuff, bytesRead);

                    if (onDataArrival != null) { onDataArrival(this, rcvBuff, bytesRead); }
                    handler.BeginReceive(_state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), _state);
                }
                else
                {
                    Stop();
                }
            }
            catch
            {
                Stop();
            }
        }

        public void Stop()
        {
            try
            {
                _state.workSocket.Shutdown(SocketShutdown.Both);
                _state.workSocket.Close();
            }
            catch
            { }
            finally
            {
                _state = null;
                onDisconnect?.Invoke(this);
            }
        }

        public void Send(byte[] data)
        {
            try
            {
                if (_state == null || _state.workSocket == null)
                {
                    return;
                }

                _state.workSocket.Send(data, 0, data.Length, SocketFlags.None);
                onSendComplete?.Invoke(this, data);
            }
            catch
            { }
        }

        public bool Send(string msg, Encoding enc = null)
        {
            try
            {
                if (_state == null || _state.workSocket == null)
                {
                    return false;
                }
                if (enc == null)
                {
                    enc = Encoding.Default;
                }
                byte[] bytesEncoded = enc.GetBytes(msg);
                _state.workSocket.Send(bytesEncoded, 0, bytesEncoded.Length, SocketFlags.None);
                onSendComplete?.Invoke(this, bytesEncoded);
                return true;
            }
            catch (Exception ex)
            {
                return false;
                throw ex;
            }
        }

    }
}

 

MSDN에서 기본 소스 참조하고, 테스트를 거친 후에 품종 개량한 것입니다.

참고 사이트
https://docs.microsoft.com/ko-kr/dotnet/framework/network-programming/asynchronous-server-socket-example
https://www.csharpstudy.com/net/article/11-%eb%b9%84%eb%8f%99%ea%b8%b0-Socket-%ec%84%9c%eb%b2%84

 

728x90

+ Recent posts