๐Ÿ™‡โ€โ™€๏ธSession

์„ธ์…˜ ์ข…ํ•ฉ๋ณธ.

๐ŸชSession

namespace ServerCore
{
    abstract class Session
    {
        Socket _socket;
        int _disconnected = 0;

        object _lock = new object();
        Queue<byte[]> _sendQueue = new Queue<byte[]>();
        List<ArraySegment<byte>> _pendingList = new List<ArraySegment<byte>>();
        SocketAsyncEventArgs _sendArgs = new SocketAsyncEventArgs();
        SocketAsyncEventArgs _recvArgs = new SocketAsyncEventArgs();

        public abstract void OnConnected(EndPoint endPoint);
        public abstract void OnRecv(ArraySegment<byte> buffer);
        public abstract void OnSend(int numOfBytes);
        public abstract void OnDisconnected(EndPoint endPoint);

        public void Start(Socket socket)
        {
            _socket = socket;

            _recvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnRecvCompleted);
            _recvArgs.SetBuffer(new byte[1024], 0, 1024);

            _sendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendCompleted);

            RegisterRecv();
        }

        public void Send(byte[] sendBuff)
        {
            lock (_lock)
            {
                _sendQueue.Enqueue(sendBuff);
                if (_pendingList.Count == 0)
                    RegisterSend();
            }
        }

        public void Disconnect()
        {
            if (Interlocked.Exchange(ref _disconnected, 1) == 1)
                return;

            OnDisconnected(_socket.RemoteEndPoint);
            _socket.Shutdown(SocketShutdown.Both);
            _socket.Close();
        }

        #region ๋„คํŠธ์›Œํฌ ํ†ต์‹ 

        void RegisterSend()
        {
            _pendingList.Clear();
            while (_sendQueue.Count > 0)
            {
                byte[] buff = _sendQueue.Dequeue();
                _pendingList.Add(new ArraySegment<byte>(buff, 0, buff.Length));
            }
            _sendArgs.BufferList = _pendingList;

            bool pending = _socket.SendAsync(_sendArgs);
            if (pending == false)
                OnSendCompleted(null, _sendArgs);
        }

        void OnSendCompleted(object sender, SocketAsyncEventArgs args)
        {
            lock (_lock)
            {
                if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
                {
                    try
                    {
                        _sendArgs.BufferList = null;
                        _pendingList.Clear();

                        OnSend(_sendArgs.BytesTransferred);

                        if (_sendQueue.Count > 0)
                            RegisterSend();

                    }
                    catch (Exception e)
                    {
                        Console.WriteLine($"OnSendCompleted Failed {e}");
                    }
                }
                else
                {
                    // TODO DIsconnect
                    Disconnect();
                }
            }
        }

        void RegisterRecv()
        {
            bool pending = _socket.ReceiveAsync(_recvArgs);
            if (pending == false)
                OnRecvCompleted(null, _recvArgs);
        }

        void OnRecvCompleted(object sender, SocketAsyncEventArgs args)
        {

            if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
            {
                try
                {
                    OnRecv(new ArraySegment<byte>(args.Buffer, args.Offset, args.BytesTransferred));
                    RegisterRecv();
                }
                catch (Exception e)
                {
                    Console.WriteLine($"OnRecvCompleted Failed {e}");
                }
            }
            else
            {
                Disconnect();
            }
        }

        #endregion
    }
}

๐Ÿช๋ถ„์„

  • Session1 - Recv

    • SocketAsyncEventArgs๋Š” ๋…๋ฆฝ์ ์ด์—ฌ์„œ ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ๋งŒ๋“ค๋ฉด ๊ฐ์ž๊ฐ€ ์ผ์„ ํ•จ - ์“ฐ๋ ˆ๋“œ์ฒ˜๋Ÿผ ์ƒ๊ฐํ•˜๋ฉด ๋ ๋“ฏ

    • Async๊ณ„์—ด์˜ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ  AsyncEventArgs๋ฅผ ๋„ฃ์–ด ์ค€ ๊ฒฝ์šฐ ์ฝœ๋ฐฑํ•จ์ˆ˜๋Š” ๋ณ„๋„์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋งŒ๋“ ๋‹ค

    • Session์œผ๋กœ ๋งŒ๋“  ๋ถ€๋ถ„์€ Receive, Send, Disconnect

  • Session2 - Send

    • Send๋Š” ๊ทธ ์‹œ์ ์— RegisterSend๋ฅผ ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์คŒ - SocketAsyncEvent๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด ์ฃผ๊ณ  SetBuffer๋ฅผ ํ•œ ํ›„ RegitserSend

    • => ์žฌ์‚ฌ์šฉ ํ•  ์ˆ˜ ์—†์Œ, ๋ถ€ํ•˜๊ฐ€ ํผ(๋„คํŠธ์›Œํฌ ์†ก์ˆ˜์‹  ๋ถ€๋ถ„์ด ๋ถ€ํ•˜๊ฐ€ ํผ), ์œ ์ €๋ชจ๋“œ์—์„œ ๋„คํŠธ์›Œํฌ ํŒจํ‚ท์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์˜ ๋ณดํ†ต ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  ์ด๋Ÿฐ๊ฒƒ๋“ค์€ ์šด์˜์ฒด์ œ๊ฐ€ ์ปค๋„๋‹จ์—์„œ ํ•จ

    • => SocketAsyncEventArgs๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๋ญ‰์ณ์„œ ๋ณด๋‚ด๊ณ  ์‹ถ๋‹ค!! ( SocketAsyncEventArgs )๋ฅผ ๋ฐ–์œผ๋กœ ๋นผ์ž

    • Queue๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ฐจ๊ณก์ฐจ๊ณก ์Œ“์•„์„œ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌ ๋˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ( OnSendCompleted๊ฐ€ ๋๋‚˜๊ธฐ ์ „๊นŒ์ง€ ๋ณด๋‚ด์ง€ ์•Š๊ณ  Queue์— ์Œ“๊ธฐ)

    • Send๋Š” ์–ธ์ œ ์‚ฌ์šฉ๋ ์ง€ ์˜ˆ์ธก ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฏธ๋ฆฌ ๋งด๋ฒ„๋ณ€์ˆ˜๋กœ _sendArgs๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ค์ œ ์‚ฌ์šฉ๋  ๋•Œ Register์•ˆ์—์„œ _sendArgs๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹, ๋ณด๋‚ด๋Š” ์ž‘์—…์ด ์™„๋ฃŒ ๋˜์ง€ ์•Š์„ ๋•Œ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋ณด๋‚ด๋Š” ์ž‘์—…์„ ํ•œ๋‹ค๋ฉด ์ผ๋‹จ Queue์— ์Œ“์•„๋‘์—ˆ๋‹ค๊ฐ€ ๋‚˜์ค‘์— ์ฒ˜๋ฆฌ

  • Session3 - BufferList

    • BufferList์™€ SetBuffer๋Š” ๋™์‹œ์— ์‚ฌ์šฉ ๋ชปํ•จ

    • ArraySegment : ์–ด๋–ค Array์˜ ์ผ๋ถ€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ตฌ์กฐ์ฒด - ํž™์ด ์•„๋‹ˆ๋ผ ์Šคํƒ์— ํ• ๋‹น๋จ

    • cs์€ cpp์™€ ๋‹ฌ๋ฆฌ ํฌ์ธํ„ฐ์˜ ๊ฐœ๋…์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์†Œ๋ฅผ ๋„˜๊ธฐ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ธ๋ฑ์Šค๋ฅผ ๋„˜๊ธฐ๊ณ  ํฌ๊ธฐ๋ฅผ ์ •ํ•จ - ex) new ArraySegment (buff, 0, buff.Length)

  • Session4 - ์ถ”์ƒํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์ด๋ฒคํŠธํ˜•์‹์œผ๋กœ ์ฝœ๋ฐฑํ•˜๊ธฐ

    • abstract ํด๋ž˜์Šค๋Š” ๋ง‰๋ฐ”๋กœ ์‚ฌ์šฉ ๋ชปํ•จ

    • ์ฝœ๋ฐฑํ˜•์‹์„ ์ทจํ•˜๊ธฐ ์œ„ํ•ด Session์„ ์ƒ์†๋ฐ›์€ GameSession์„ ๋งŒ๋“ค์–ด์„œ ์ถ”์ƒํด๋ž˜์Šค ๊ตฌํ˜„

    • _sessionFactory ์„ธ์…˜์„ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ๋ˆ„๊ตฌ๋ฅผ ๋งŒ๋“ค์–ด ์ค„์ง€ ์ •์˜ํ•˜๋Š” Func( out ๊ฒฐ๊ณผ๊ฐ’์ด ์žˆ์Œ ) => ์„ธ์…˜์„ ๋ˆ„๊ตฌ๋ฅผ ๋งŒ๋“ค์–ด์ค„์ง€ ์ •์˜ํ•˜๋ฉด์„œ ์‚ฌ์šฉํ•ด์•ผ ๋จ ( _listner.Init(endPoint, () => { return new GameSession(); }

    • ์ปจํ…์ธ ๋‹จ๊ณผ ์—”์ง„๋‹จ์„ ๊ตฌ๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ ์ž‘์—…๋“ค!

    • -> Session session = _sessionFactory.Invoke(); ์‚ฌ์šฉ๊ฐ€๋Šฅ, ์–ด๋–ค ์„ธ์…˜์„ ๋งŒ๋“ค์ง€ ๋ชจ๋ฅด๋‹ˆ๊นŒ Session์„ ๋ฑ‰๋Š” _sessionFactory๋ฅผ ๋งŒ๋“ ๊ฒƒ์ด ํฌ์ธํŠธ

ํƒœ๊ทธ:

์นดํ…Œ๊ณ ๋ฆฌ:

์—…๋ฐ์ดํŠธ: