如何为底层的UDP套接字设置缓冲区大小?C#

9

我们知道,在接收UDP数据时,可以使用Socket.ReceiveFrom或UdpClient.receive函数。

Socket.ReceiveFrom函数需要你提供一个字节数组,用于存放UDP数据。

UdpClient.receive函数直接返回包含数据的字节数组。

我的问题是如何在Socket内部设置缓冲区大小。我认为操作系统维护了自己的缓冲区来接收UDP数据,对吗?例如,如果有一个UDP数据包发送到我的计算机,操作系统会将其放入缓冲区,并等待我们执行Socket.ReceiveFrom或UdpClient.receive函数,对吗?

我该如何更改该内部缓冲区的大小呢?

我尝试过使用Socket.ReceiveBufferSize,但它对UDP没有任何影响,并且它明确说明它是针对TCP窗口的。此外,我已经进行了许多实验,证明Socket.ReceiveBufferSize不适用于UDP。

有人能分享一些关于UDP内部缓冲区的见解吗?

谢谢。

我在这里看到了一些帖子,例如:

http://social.msdn.microsoft.com/Forums/en-US/ncl/thread/c80ad765-b10f-4bca-917e-2959c9eb102a

戴夫说Socket.ReceiveBufferSize可以设置UDP的内部缓冲区。我不同意。
我的实验是这样的:
27个主机在同一时间(至少几乎)在局域网内向我发送一个10KB的udp数据包。我有一个while循环来处理每个数据包。对于每个数据包,我创建一个线程来处理它。我使用UdpClient或Socket接收数据包。
我丢失了大约50%的数据包。我认为这是UDP发送的爆发,我无法及时处理所有数据包。
这就是为什么我想增加UDP的缓冲区大小。比如说,如果我将缓冲区大小改为1MB,那么可以在缓冲区中接受27 * 10KB = 270KB的数据,对吧?
我尝试将Socket.ReceiveBufferSize更改为许多值,但根本没有任何效果。
有人能帮忙吗?
2个回答

11

我经常使用.NET的UDPClient,一直使用Socket.ReceiveBufferSize并取得了良好的效果。内部它使用Socket.SetSocketOption调用ReceiveBuffer参数。以下是一些快速简单的代码,您可以进行测试:

public static void Main(string[] args)
{
  IPEndPoint remoteEp = null;
  UdpClient client = new UdpClient(4242);
  client.Client.ReceiveBufferSize = 4096;

  Console.Write("Start sending data...");
  client.Receive(ref remoteEp);
  Console.WriteLine("Good");

  Thread.Sleep(5000);
  Console.WriteLine("Stop sending data!");
  Thread.Sleep(1500);

  int count = 0;
  while (true)
  {
    client.Receive(ref remoteEp);
    Console.WriteLine(string.Format("Count: {0}", ++count));
  }
}

请尝试调整传递给ReceiveBufferSize的值。 我测试了连续发送数据5秒钟,得到了10个数据包。 然后我将其增加了4倍,下一次得到了38个数据包。
我建议您查看网络中可能丢失数据包的其他地方。特别是因为您在其他帖子中提到发送了10KB数据包。 当它被发送到MTU大小的数据包时,这10KB将被分成片段。 如果该系列中有任何1个数据包丢失,则整个数据包将被丢弃。

@heavyd:感谢您的回复。 我的代码与您的非常相似。但如果您有兴趣,可以进行一个简单的实验。 我们分别有两个类-服务器和客户端。在您的Client.cs中,您只需使用UdpClient将200个数据包(每个10KB)发送到本地端口8888。(无论您想要哪个端口)在您的Server.cs中,您像您的代码所示一样不断接收当然,请先运行您的server.cs。我的结果是90%的数据包可以被接收。关键是UDP发送是突发性的,太多的数据包到达,您的服务器无法处理,并且缓冲区溢出。 - Jack
是的,你是说将ReceiveBufferSize从一个值(比如4096)调整到更高的值(比如4 * 4096)没有任何作用吗? - heavyd
@heavyd:在上面的本地实验中,如果没有设置ReceiveBufferSize,仅能接收90%的数据包。但如果将其增加到16 * 4096,则可以接收所有数据包。但在我的原始实验中,它并没有起作用。 - Jack
@Jack,我不能确定上限。我最初的猜测是64K,但我找不到任何支持文件。在您的实验之后,您确定您的网络没有在数据包到达计算机之前将其丢弃吗?您可能会在混合物中饱和某个交换机并在那里丢失数据包,而不是在计算机堆栈上丢失。 - heavyd
@heavyd,不,我不确定。我只是认为这不太可能,因为它是局域网。 无论如何,我可以问你,如果我的上传带宽是50KB/s,并且我以非常快的速度向您发送27个数据包(每个10KB),您是否能够全部接收?我只是想弄清楚UDP是如何工作的。套接字会缓冲发送吗? - Jack
显示剩余2条评论

8

设置ReceiveBufferSize的问题在于需要在创建UdpClient对象后直接设置它。我曾经遇到过同样的问题,当获取ReceiveBufferSize的值时没有反映出我所做的更改。

UdpClient client = new UdpClient()
//no code inbetween these two lines accessing client.
client.Client.ReceiveBufferSize = somevalue

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接