Я сейчас работаю на TCP-сервере, используя сокеты в C#. Я столкнулся с проблемой, и я не могу ее решить ..
Мой сервер принимает подключения и создает новый NetEntity для каждого клиента. Эти NetEntities обрабатывают отправку / получение пакетов и обновляются в al oop, который тикает 30 раз в секунду.
Проблема: после подключения 4-го клиента я получаю это исключение (только для 4-го NetEntity).
Асинхронная операция с сокетом уже выполняется с использованием этого экземпляра SocketAsyncEventArgs.
Если я использую if (Interlocked.Read(ref m_sending) == 1) return;
, чтобы убедиться, что он завершил отправку, 4-й NetEntity никогда не отправляет никаких данных , При удалении этой строки возникает исключение.
Я просто не могу правильно обернуть голову, используя SendAsync
и SocketAsyncEventArgs
с фиксированной скоростью тика.
public void Send(Packet packet)
{
OutgoingQueue.Enqueue(packet);
}
private void QueueSend()
{
Interlocked.Exchange(ref m_sending, 1);
var sendTask = new Task(Send);
sendTask.ContinueWith((t) => t.Dispose());
sendTask.Start();
}
private void Send()
{
if (Interlocked.Read(ref m_sending) == 1) return;
if (!Socket.Connected) return;
if (OutgoingQueue.TryDequeue(out var packet))
{
packet.Serialize(m_packetWriter);
}
var writerBuffer = m_packetWriter.ToArray();
Array.Copy(writerBuffer, m_sendBuffer, writerBuffer.Length);
try
{
SendArgs.SetBuffer(SendArgs.Offset, writerBuffer.Length);
if (!Socket.SendAsync(SendArgs))
{
SendCompleted(Socket, SendArgs);
}
}
catch (SocketException)
{
//Client disconnect
}
catch (Exception ex)
{
Log.Error($"NetEntity {m_id} send exception: {ex.Message} - {ex.StackTrace} - {ex.InnerException}");
}
}
private void SendCompleted(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
if (OutgoingQueue.Count > 0)
{
//QueueSend();
}
m_packetWriter.Reset();
}
else
{
Interlocked.Exchange(ref m_sending, 0);
}
}
Настройка выглядит следующим образом
SendArgs = new SocketAsyncEventArgs();
SendArgs.SetBuffer(m_sendBuffer, 0, BufferSize);
SendArgs.Completed += SendCompleted;
Я ценю любую помощь и улучшения кода.
Спасибо!