这是与C# UDP packetloss though all packets arrive (WireShark)相同的问题,除了我将ReceiverBuffer
设置为10MB,我还监控Socket.Available
,显示缓冲区甚至达不到200k利用率。
在一个简单的测试案例中,使用tcpreplay以40Mbps的速率发送相同的小(多播)UDP数据包(净数据大小:137)25,000次,通常不是所有数据包都到达我的程序,尽管所有数据包都到达Wireshark ,我在那个盒子上同时跑。有时它只丢失了一个数据包,有时它只有十几个,有时甚至更多。
守则
static void Main()
{
int udpPacketsReceived = 0;
var bindAddress = IPAddress.Parse("192.168.20.54");
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.ReceiveBufferSize = 10485760; // 10M
socket.Bind(new IPEndPoint(bindAddress, 51001));
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("239.193.1.1")));
Console.WriteLine("Effective ReceiveBuffer size: " + socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer));
var t = new Thread(ipAndClient =>
{
var buffer = new byte[2000];
int maxAvail = 0;
while (true)
{
socket.Receive(buffer);
Interlocked.Increment(ref udpPacketsReceived);
var available = socket.Available;
if (available > maxAvail)
{
Console.WriteLine("available new max: " + available);
maxAvail = available;
}
}
});
t.Start();
int lastValue = -1;
while (true)
{
var newValue = Thread.VolatileRead(ref udpPacketsReceived);
if (newValue != lastValue)
{
Console.WriteLine("Total UDP packets received: {0}", newValue);
lastValue = newValue;
}
Thread.Sleep(1000);
}
}
示例输出
Effective ReceiveBuffer size: 10485760
Total UDP packets received: 0
available new max: 685
available new max: 3288
available new max: 3836
available new max: 6165
available new max: 8220
available new max: 10960
Total UDP packets received: 14307
available new max: 18632
available new max: 140425
available new max: 141521
available new max: 143439
Total UDP packets received: 24996
出了什么问题?
重要添加(事后证明这一点至关重要,请参阅my own answer):我使用&#34在VirtualBox主机中的Windows来宾上运行桥连#34;虚拟网卡。
答案 0 :(得分:1)
Wireshark在数据包传递到协议堆栈之前获取数据包,而接收缓冲区则在内核协议堆栈的末尾。有很多内存分配和其他处理在高负载上进行,它可能只是在一些数据包到达接收缓冲区之前丢弃它们。
Winsock图层位于传输层的顶部。可以在网络堆栈中的各个层丢弃数据报。
答案 1 :(得分:0)
Steffen Ullrich的回答和评论让我深入研究了我的系统设置 - 在VirtualBox中运行的Windows 8.1 - 我发现对于我的工作负载,最高可达50Mbps和20kpps,我可以摆脱通过将虚拟网卡从“桥接”更改为“Paravirtualized network adapter (virtio-net)”来丢弃所有数据包丢失。
这需要在Windows guest虚拟机中安装网络驱动程序。驱动程序,可以通过http://www.linux-kvm.org/page/WindowsGuestDrivers/Download_Drivers下载。获取二进制数字签名驱动程序的最简单方法是单击该页面上的“Fedora”链接,然后安装“netkvm.inf”,即 Red Hat VirtIO以太网适配器驱动程序,适用于您的操作系统。