开发者

Socket.SendAsync is not sending in-order on Mono/Linux

开发者 https://www.devze.com 2023-02-08 03:07 出处:网络
There is a a single-threaded server using .NET Socket with TCP protocol, and Socket.Pool(), Socket.Select(), Socket.Receive().

There is a a single-threaded server using .NET Socket with TCP protocol, and Socket.Pool(), Socket.Select(), Socket.Receive().

To send, I used:

public void SendPacket(int clientid, byte[] packet)
{
    clients[clientid].socket.Send(packet);
}

But it was very slow when sending a lot of data to one client (halting the whole main thread), so I replaced it with this:

public void SendPacket(int clientid, byte[] packet)
{
    using (SocketAsyncEventArgs e = new SocketAsyncEventArgs())
    {
        e.SetBuffer(packet, 0, packet.Length);
        clients[clientid].socket.SendAsync(e);
    }
}

It works fine on Windows with .NET (I don't know if 开发者_JS百科it's perfect), but on Linux with Mono, packets are either dropped or reordered (I don't know). Reverting to slow version with Socket.Send() works on Linux. Source for whole server.

How to write non-blocking SendPacket() function that works on Linux?


I'm going to take a guess that it has to do with your using statement and your SendAsync call. Perhaps e falls out of scope and is being disposed while SendAsync is still processing the buffer. But then this might throw an exception. I am really just taking a guess. Try removing the using statement and see what happens.


I would say by not abusing the async method. YOu will find nowhere a documentation stating that this acutally is forced to maintain order. it queues iem for a scheuler which get distributed to threads, and by ignoring that the oder is not maintained per documentation you open yourself up to implementation details.

The best possibly is to:

  • Have a queue per socket.
  • When you write dasta into this queue, and there is no worker thread, start a work item (ThreadPool) to process the thread.

This way you have separate distinct queues that maintain order. Only one thread will ever process one queue / socket.


I got the same problem; Linux and windows react not in the same way with SendAsync. Sometimes linux truncate the data, but there is a workaround. First of all you need to use a queue. Each time you use SendAsync you have to check the callback. If e.Offset + e.BytesTransferred < e.Buffer.Length, you just have to e.SetBuffer(e.Offset + e.BytesTransferred, e.Buffer.Length - e.BytesTransferred - e.Offset); and call SendAsync again.

I dont know why mono-linux believe it's completed before sending all the data and it's strange but i'm sure he does.


just like @mathieu, 10y later, I can confirm on Unity Mono+Linux complete callback is called without all bytes being sent in some cases. For me it was large packets only.

0

精彩评论

暂无评论...
验证码 换一张
取 消