UnityServer - 비동기 Listener

k_hyun·2022년 10월 31일
0

Unity_Server

목록 보기
14/32

Listener.cs

        Socket _listenSocket;
        Action<Socket> _onAcceptHandler;

        public void Init(IPEndPoint endPoint, Action<Socket> onAcceptHandler)
        {
            _listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            _onAcceptHandler += onAcceptHandler;

            // 문지기 교육
            _listenSocket.Bind(endPoint);

            // 영업시작
            // backlog : 최대 대기수
            _listenSocket.Listen(10);

            // AcceptAsync에 필요한 것
            SocketAsyncEventArgs args = new SocketAsyncEventArgs();
            
            // Accept가 완료되면 실행할 이벤트
            args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
            RegisterAccept(args);
        }

args.Completed는 Accept가 완료되면 실행할 이벤트를 설정하는 핸들러이다.

        void RegisterAccept(SocketAsyncEventArgs args)
        {
            args.AcceptSocket = null;

            bool pending = _listenSocket.AcceptAsync(args);
            if (pending == false)
                OnAcceptCompleted(null, args);
        }

Init함수에서 실행될 함수이다.

_listen소켓을 비동기 방식으로 Accept한다.

이후 클라에서 Connect가 되면 OnAccpetCompleted 함수를 실행한다.

pending 변수는 Accpet 이후에 바로 Connect가 되는 경우를 처리하기 위해 사용하였다.

        void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
        {
            if (args.SocketError == SocketError.Success)
            {
                // 생성된 소켓을 매개변수로 사용
                _onAcceptHandler.Invoke(args.AcceptSocket);
            }
            else
                Console.WriteLine(args.SocketError.ToString());

            // Accept되면 다시 Register한다.
            RegisterAccept(args);
        } 

이벤트 핸들러는 매개변수로 sender, args가 필요하기에 넣어주었다.

Accept가 완료되면 _onAcceptHandler에 연결된 함수를 실행한다.

이후 다시 Accept 등록을 실시한다.

Program.cs

namespace SeverCore
{    
    internal class Program
    {
        static Listener _listener = new Listener();

        static void OnAcceptHandler(Socket clientSocket)
        {
            try
            {
                // 받는다
                byte[] recvBuff = new byte[1024];
                int recvBytes = clientSocket.Receive(recvBuff);
                string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes);
                Console.WriteLine($"[From Client] {recvData}");

                // 보낸다
                byte[] sendBuff = Encoding.UTF8.GetBytes("Welcome to MMORPG Server!");
                clientSocket.Send(sendBuff);

                // 쫓아낸다
                clientSocket.Shutdown(SocketShutdown.Both);
                clientSocket.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            
        }

Listener에서 사용할 이벤트 함수이다.

생성된 소켓을 사용하여 데이터를 주고받는 부분을 이쪽에 넣었다.

        static void Main(string[] args)
        {
            // DNS (Domain Name System)
            string host = Dns.GetHostName();            
            IPHostEntry ipHost = Dns.GetHostEntry(host);            
            IPAddress ipAddr = ipHost.AddressList[0];            
            IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777);

            _listener.Init(endPoint, OnAcceptHandler);
            Console.WriteLine("Listening...");
            while (true)
            {
                
            }       
        }

Init함수를 실시하여 비동기적으로 Accept를 실시한다.

실행


잘 작동함을 확인하였다.

0개의 댓글