SendAsyn c и SocketAsyncEventArgs корректно используют фиксированный тикрейт - PullRequest
0 голосов
/ 27 марта 2020

Я сейчас работаю на 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;

Я ценю любую помощь и улучшения кода.

Спасибо!

...