什么会导致UDP数据包被发送到localhost时被丢弃?

我正在发送非常大(64000字节)的数据报。 我意识到MTU远小于64000字节(典型值大约是1500字节,从我的读数开始),但我怀疑会发生两件事之一 – 要么没有数据报就能通过(所有大于1500字节)会被静默删除或导致抛出错误/exception)或64000字节数据报将被分成大约43个1500字节的消息并透明地传输。

从长远来看(2000+ 64000字节数据报),数据报的大约1%(即使是LAN似乎exception高)也会被丢弃。 我可能期望通过网络,数据报可能无序到达,被丢弃,过滤等等。 但是,在localhost上运行时我没想到这一点。

是什么导致无法在本地发送/接收数据? 我意识到UDP是不可靠的,但我没想到它在localhost上如此不可靠。 我想知道它是否只是一个时间问题,因为发送和接收组件都在同一台机器上。

为了完整起见,我已经包含了发送/接收数据报的代码。

发送:

DatagramSocket socket = new DatagramSocket(senderPort); int valueToSend = 0; while (valueToSend < valuesToSend || valuesToSend == -1) { byte[] intBytes = intToBytes(valueToSend); byte[] buffer = new byte[bufferSize - 4]; //this makes sure that the data is put into an array of the size we want to send byte[] bytesToSend = concatAll(intBytes, buffer); System.out.println("Sending " + valueToSend + " as " + bytesToSend.length + " bytes"); DatagramPacket packet = new DatagramPacket(bytesToSend, bufferSize, receiverAddress, receiverPort); socket.send(packet); Thread.sleep(delay); valueToSend++; } 

接收:

 DatagramSocket socket = new DatagramSocket(receiverPort); while (true) { DatagramPacket packet = new DatagramPacket( new byte[bufferSize], bufferSize); System.out.println("Waiting for datagram..."); socket.receive(packet); int receivedValue = bytesToInt(packet.getData(), 0); System.out.println("Received: " + receivedValue + ". Expected: " + expectedValue); if (receivedValue == expectedValue) { receivedDatagrams++; totalDatagrams++; } else { droppedDatagrams++; totalDatagrams++; } expectedValue = receivedValue + 1; System.out.println("Expected Datagrams: " + totalDatagrams); System.out.println("Received Datagrams: " + receivedDatagrams); System.out.println("Dropped Datagrams: " + droppedDatagrams); System.out.println("Received: " + ((double) receivedDatagrams / totalDatagrams)); System.out.println("Dropped: " + ((double) droppedDatagrams / totalDatagrams)); System.out.println(); } 

是什么导致无法在本地发送/接收数据?

主要是缓冲空间。 假设您发送的是10MB /秒的常量,并且您只能消耗5MB /秒,操作系统和网络堆栈无法跟上,因此它会丢弃数据包 – 这应该是相当明显的。 (这自然不同于提供流量控制和重传以处理这种情况的TCP)。

即使您通常不断使用数据,也可能会有很少的时间片。 例如,一个垃圾收集器启动,操作系统决定安排另一个进程而不是你的消费者0.5秒等等 – 系统将丢弃数据包。

这可以扩展到其间的任何网络设备。 如果您在网络上运行而不是仅在本地运行,则以太网交换机,路由器等也会在其队列已满时丢弃数据包(例如,您通过100MB / s以太网交换机发送10MB / s的流,并且在半夜的几秒钟,其他人试图通过相同的路径填充100MB /秒,一些数据包将丢失。)

尝试增加套接字缓冲区大小 ,通常你也必须在操作系统级别增加它。

(例如在linux上,默认的套接字缓冲区大小通常只有128k或更小,这为暂停数据处理留下了很小的空间,你可以尝试通过设置sysctl net.core.wmem_max,net.core.wmem_default来增加它们, net.core.rmem_max,net.core.rmem_default)

UDP pkts调度可以由OS级别上的多个线程处理。 这可以解释为什么即使在127.0.0.1上也无法接收它们。

我不知道是什么让你期望UDP的丢弃数据包的百分比低于1%。

话虽如此,基于RFC 1122 (参见第3.3.2节 ),保证不分成多个IP数据报的最大缓冲区大小为576字节。 可以传输较大的UDP数据报,但是它们很可能被分成多个IP数据报,以便在接收端点重新组装。

我认为有一个原因导致您看到的丢包率很高 ,如果丢失一个大型UDP数据报的IP数据包,整个UDP数据报就会丢失。 而且你在计算UDP数据报 – 而不是IP数据包。

您的问题以及对其他答案的众多评论中表达的您的期望是错误的。 即使没有路由器和电缆,也会发生以下所有情况。

  1. 如果您向任何接收器发送数据包并且其套接字接收缓冲区中没有空间,它将被丢弃。

  2. 如果发送的UDP数据报大于路径MTU,则会将其分段为较小的数据包,这些数据包受(1)的影响。

  3. 如果数据报的所有数据包都没有到达,则数据报永远不会被传递。

  4. TCP / IP堆栈没有义务按顺序传送数据包或UDP数据报。

UDP数据包不能保证到达目的地而TCP是!