UnityServer - SendAsync (1)

k_hyun·2022년 10월 31일
0

Unity_Server

목록 보기
16/32

Session.cs

namespace SeverCore
{    
    internal class Session
    {
        Socket _socket;
        int _disconnected = 0;

        object _lock = new object();
        Queue<byte[]> _sendQueue = new Queue<byte[]>();
        bool _pending = false;
        SocketAsyncEventArgs _sendArgs = new SocketAsyncEventArgs();

        public void Start(Socket socket)
        {            
            _sendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendCompleted);            
        }

보낼 buffer들은 Queue에다가 넣어서 저장한다.

        public void Send(byte[] sendBuff)
        {
            lock (_lock)
            {
                _sendQueue.Enqueue(sendBuff);
                // 첫빠따인 경우
                if (_pending == false)
                    RegisterSend();
            }            
        }        

처음으로 큐에 집어넣는 경우 바로 RegisterSend를 실행한다.

        void RegisterSend()
        {
            _pending = true;
            byte[] buff = _sendQueue.Dequeue();
            _sendArgs.SetBuffer(buff, 0, buff.Length);

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

큐에서 버퍼를 가져와서 SendAsync함수를 실행한다.

sendAsync의 반환값이 false라는 뜻은 코드 실행 이후 바로 버퍼를 보냈다는 것을 의미한다.

따라서 기다리고 있는 것이 없으므로 false가 된다.

        void OnSendCompleted(object sender, SocketAsyncEventArgs args)
        {
            lock (_lock)
            {
                if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
                {
                    try
                    {
                        if (_sendQueue.Count > 0)
                            RegisterSend();
                        else
                            _pending = false;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine($"OnSendCompleted Failed {e}");
                    }
                }
                else
                {
                    Disconnect();
                }
            }            
        }     

_sendQueue.Count가 0보다 큰 경우에는 _pending중인 버퍼가 있다는 것을 의미한다.

이는 Send함수에서 RegsiterSend를 호출하고 이때 pending이 true이고 동시에 다른 스레드에서 Send 함수를 실행하게 되면 Queue의 수가 2 이상이 될 수 있다.

위와 같은 상황이 있기에 Send가 Compelte 된다고 바로 _pending을 false로 바꾸면 안된다.

Queue가 모두 비워진 이후에만 _pending을 true로 바꿔야 한다.

0개의 댓글