C# Rookiss Part4 ๊ฒ์์๋ฒ : Session
๐โโ๏ธ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๋ฅผ ๋ง๋ ๊ฒ์ด ํฌ์ธํธ 
 
-