【问题标题】:C# UDP send/sendAsync too slowC# UDP 发送/sendAsync 太慢
【发布时间】:2015-01-12 18:05:15
【问题描述】:

我正在尝试向不同的远程主机发送 许多 小(约 350 字节)UDP 消息,每个远程主机一个数据包。我正在使用后台线程来监听响应

   private void ReceivePackets()
   {
       while (true)
       {
           try
           {
               receiveFrom = new IPEndPoint(IPAddress.Any, localPort);
               byte[] data = udpClientReceive.Receive(ref receiveFrom);
               // Decode message & short calculation
           }
           catch (Exception ex)
           {
               Log("Error receiving data: " + ex.ToString());
           }
       }
   }

和一个用于发送消息的主线程

udpClientSend.SendAsync(send_buffer, send_buffer.Length, destinationIPEP);

UdpClient udpClientReceiveUdpClient udpClientSend 都绑定到同一个端口。
问题是SendAsync() 大约需要 15 毫秒才能完成,我需要每秒发送几千个数据包。我已经尝试过使用udpClientSend.Send(send_buffer, send_buffer.Length, destination);,它同样慢。我还将接收/发送缓冲区设置得更高,我尝试设置udpClientSend.Client.SendTimeout = 1;,但没有效果。我怀疑这可能与远程主机更改每个数据包有关?如果是这样的话,在单独的线程中使用多个 UDPclient 会不会让事情变得更快?
感谢您的帮助!

注意事项: 网络带宽不是问题,我需要使用 UDP 而不是 TCP。 我在这个网站上看到过类似的问题,但没有一个令人满意的答案。

编辑

只有一个线程用于发送,它运行一个简单的循环,其中调用udpClientSend.SendAsync()
我正在查询 DHT(bittorrent 哈希表)中的节点,因此多播不是一个选项(?) - 每个主机只能获得 1 个数据包。
UDPClient 类与Socket 类交换并使用AsyncSendTo() 不会加快速度(或微不足道)。

我已经缩小了问题范围:将远程主机地址更改为某个固定 IP 和端口可将吞吐量提高到超过 3000 个数据包/秒。因此,过于频繁地更改目标地址似乎是瓶颈。

我认为我的问题可能与 UDP "Connect"-Speed in C#UDPClient.Connect() 正在减慢代码速度有关。如果是这样,是否有解决此问题的方法?是语言问题还是操作系统问题?

【问题讨论】:

  • 我对这些方法的性能了解不多,但提到 15ms 可能会引发问题。如果您使用诸如 GetTickCount() 之类的方法来计时,该时钟的分辨率约为 15 毫秒,并且不准确地测量延迟可能会让您寻找错误的解决方案。
  • 我在UdpClientSocket 中看不到任何会导致性能下降的内容。凯蒂的解释似乎很有可能。
  • 你每秒测量多少个数据包?
  • 另外,我不能代表UdpClient,但是当使用裸机方法Socket.SendToAsync 时,您可以有多个未完成的发送——这将为您提供最大的吞吐量。
  • 我正在使用 Stopwatch 类来测量时间。 15ms 是平均值,大多数消息花费的时间更少,但至少需要 3ms。 Wireshark 测量大约 200 个数据包/秒,其中只有一半是上游的。这似乎大致对应于 15ms 的数字。 @Cory Nelson:我不确定我是否理解正确,您是否建议使用额外的线程来并行调用 Socket.SendAsync()?

标签: c# performance udp


【解决方案1】:

为什么在发送之前使用 UdpClient Connect?如果要设置默认主机,这是一个可选步骤。看起来您想要发送到多个目的地,因此您可以在每次调用 Send 方法时设置远程主机。

如果您决定删除 Connect 方法,您可能会看到改进,但看起来您的代码中的其他地方仍然存在瓶颈。隔离 Send 调用并测量时间,然后开始添加更多步骤,直到找到拖慢您速度的原因。

        var port = 4242;
        var ipEndPoint1 = new IPEndPoint(IPAddress.Parse("192.168.56.101"), port);
        var ipEndPoint2 = new IPEndPoint(IPAddress.Parse("192.168.56.102"), port);
        var buff = new byte[350];
        var client = new UdpClient();

        int count = 0;
        var stopWatch = new Stopwatch();
        stopWatch.Start();
        while (count < 3000)
        {
            IPEndPoint endpoint = ipEndPoint1;
            if ((count % 2) == 0)
                endpoint = ipEndPoint2;

            client.Send(buff, buff.Length, endpoint);
            count++;
        }
        stopWatch.Stop();

        Console.WriteLine("RunTime " + stopWatch.Elapsed.TotalMilliseconds.ToString());

【讨论】:

    猜你喜欢
    • 2015-11-12
    • 1970-01-01
    • 1970-01-01
    • 2016-07-26
    • 2018-10-02
    • 2012-03-24
    • 1970-01-01
    • 1970-01-01
    • 2011-09-14
    相关资源
    最近更新 更多