C# 套接字,用于接收具有一些暂停期的 UDP 数据包

C# Socket to receive UDP packets with some pause periods

提问人:Linus 提问时间:4/13/2022 更新时间:4/13/2022 访问量:308

问:

我尝试运行 C# (.Net 4.8) 程序来接收来自服务器的 UDP 数据包。数据包频繁发送(每个数据包约 20 毫秒),每个数据包约 100 字节。

我的程序可以正常接收它们。但是,在接收了大约 100-200 个数据包后,它在大约 3 秒内无法接收,因此丢失了相当多的数据包。我计算了一下,如果我们发送了 1000 个数据包,只能接收大约 600-700 个数据包。

但是,如果我停止客户端程序,我可以从 Wireshark 中看到我的 PC 可以顺利接收数据包而不会出现任何停顿。

我的代码类似如下:

internal class StateObject
{
   internal Socket workSocket = null;
   internal const int BufferSize = 300;
   internal byte[] buffer = new byte[BufferSize];
}

private void Connect()
{
   IPAddress objIPAddress = IPAddress.Parse(mstrServername);
   mobjIPEndPointUdp = new IPEndPoint(objIPAddress, miUdpPort);
   mobjUdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
   mobjUdpSocket.ReceiveBufferSize = 0x10000;
   mobjUdpSocket.Connect(mobjIPEndPointUdp);

   // Create a new thread to call RecvUdpFunc to receive UDP packets...
}

private void RecvUdpFunc()
{
   byte[] arb = null;
   try
   {
      StateObject state = new StateObject();
      state.workSocket = mobjUdpSocket;
      mobjUdpSocket.BeginReceiveFrom(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, ref mobjEndPointUdp, new AsyncCallback(RecvUdp), state);
   }
   catch
   {

   }
}

private void RecvUdp(IAsyncResult result)
{
   byte[] arb = null;

   try
   {
      StateObject state = (StateObject)result.AsyncState;
      Socket client = state.workSocket;
      int bytes = client.EndReceiveFrom(result, ref mobjEndPointUdp);

      client.BeginReceiveFrom(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, ref mobjEndPointUdp, new AsyncCallback(RecvUdp), state);
      if (bytes > 0)
      {
         arb = new byte[bytes];
         Array.Copy(state.buffer, arb, bytes);
         // Process the object arb by queuing it to another thread...
      }
   }
   catch (Exception ex)
   {

   }
}

请帮忙。谢谢。

c#

评论

0赞 Ilian 4/13/2022
看起来可能存在争用条件,而异步使用 。也许将整个 if 块移动到之前。Array.Copy(state.buffer, arb, bytes);BeginReceiveFromstate.bufferBeginReceiveFrom
0赞 Dai 4/13/2022
300 字节对于网络接收缓冲区来说有点小 - 它也不是 2 的幂,所以它可能是次优的 - 通常你应该把它调整为 4096 的倍数。请考虑使用 65535 字节(即 64KB 大小)的缓冲区,因为它与 UDP 的最大数据报长度相匹配。
0赞 Dai 4/13/2022
你不能有一个空块 - 这意味着你正在吞噬异常,这可能是它不起作用的原因。catch
0赞 Linus 4/13/2022
我试图将 BeginReceiveFrom 行放在 if (bytes > 0) 块之后。此外,缓冲区更改为 4096,并删除了 try catch 块。情况似乎有所改善,但仍远未达到预期。
0赞 Linus 4/14/2022
我刚刚尝试禁用行“mobjUdpSocket.BeginReceiveFrom(...”)在函数 RecvUdpFunc 中,即不在我的程序中接收任何数据包,而只是使用 Wireshark 监控数据包流。我发现它确实像我的程序一样暂停。似乎是 Windows 或我的硬件的问题?我认为这很奇怪,因为我认为这不仅仅是我的问题。

答: 暂无答案