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로 바꿔야 한다.