0

im currently working on a TCP Server using Sockets in C#. I encountered a problem and i'm not able to solve it..

My Server accepts connections and creates a new NetEntity for each client. These NetEntities handle Sending/Receive packets and are updated in a loop that ticks 30 times per second.

Problem : After the 4th client is connected i receive this exception(only on the 4th NetEntity).

An asynchronous socket operation is already in progress using this SocketAsyncEventArgs instance.

If i use if (Interlocked.Read(ref m_sending) == 1) return; to make sure it is done sending, the 4th NetEntity never send any data. When deleting this line the exception occurs.

I just cant wrap my head around using SendAsync and SocketAsyncEventArgs properly with a fixed tickrate.

        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);
            }
        }

Setup looks like this

    SendArgs = new SocketAsyncEventArgs();
    SendArgs.SetBuffer(m_sendBuffer, 0, BufferSize);
    SendArgs.Completed += SendCompleted;

I appreciate any help and code Improvements.

Thanks!

  • 1
    You might find it simpler to create a new Thread for each connected socket and use use the synchronous APIs. It's a fundamentally simpler model, and has equivalent performance for small (10s to 100s) numbers of connected clients. – David Browne - Microsoft Mar 27 '20 at 16:01
  • 1
    I will disagree with the suggestion to go to a "one thread per connection" model. However, I _will_ agree with the implied suggestion that you should avoid the socket's `...Async` model. That's for very-high-volume scenarios, which does not seem to be the case here, and it can be very tricky to get right (as you've seen). A good intermediate option is to use the TPL async/await model; this can be done using `TaskFactory.FromAsync()` on the socket objects directly, or by wrapping the socket in a `NetworkStream` and then using the TPL-compatible `...Async` methods there. – Peter Duniho Mar 27 '20 at 17:13
  • 1
    As for this question, it's way too broad, and unanswerable due to the lack of a [mcve] that reliably reproduces the problem. You've clearly mis-managed your pool of `SocketAsyncEventArgs` objects somehow, but beyond that, there's no way to know exactly what needs fixing without a better question. – Peter Duniho Mar 27 '20 at 17:14
  • Thanks for the Answer, i'll go for the simpler model. I just got another question. How would you guys implement tick based sending ? Like queue up all packages and every tick send all packages with one "Send" call or limit the amount of packages that can be send each tick ? Its hard to find any resources about this topic, some examples would be just fine for me but i couldn't find any. –  Mar 27 '20 at 18:31

0 Answers0