我正在发送非常大的(64000字节)数据报。我意识到MTU远小于64000字节(典型值大约是1500字节,来自我的读数),但我怀疑会发生两件事之一 - 要么没有数据报就能通过(所有大于1500字节)将被静默删除或导致抛出错误/异常)或64000字节数据报将被分成大约43个1500字节的消息并透明地传输。
从长远来看(2000+ 64000字节数据报),数据报的大约1%(即使是LAN似乎异常高)也会被丢弃。我可能期望通过网络,数据报可能无序到达,被丢弃,过滤等等。但是,在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();
}
答案 0 :(得分:27)
是什么导致无法在本地发送/接收数据?
主要是缓冲空间。假设您正在发送一个10MB /秒的恒定速度,并且您只能消耗5MB /秒,操作系统和网络堆栈无法跟上,因此它会丢弃数据包 - 这应该是相当明显的。 (这自然不同于提供流量控制和重传来处理这种情况的TCP。)
即使您通常不断使用数据,也可能会有一些小的时间片。例如一个垃圾收集器启动,操作系统决定安排另一个进程而不是你的消费者0.5秒,等等 - 系统将丢弃数据包。
这可以扩展到其间的任何网络设备。如果您在网络上运行而不是仅在本地运行,则以太网交换机,路由器等也会在其队列已满时丢弃数据包(例如,您通过100MB / s以太网交换机发送10MB / s的流,并且在半夜的几秒钟,其他人试图通过相同的路径填充100MB /秒,一些数据包将丢失。)
尝试增加socket buffers size,通常你也必须在操作系统级别上增加它。
(例如在Linux上,默认的套接字缓冲区大小通常只有128k或更小,这使得非常暂停数据处理的空间很小,您可以尝试通过设置{{3来增加它们}} net.core.wmem_max,net.core.wmem_default,net.core.rmem_max,net.core.rmem_default)
答案 1 :(得分:4)
UDP pkts调度可以由OS级别的多个线程处理。这就解释了为什么即使在127.0.0.1上也无法接收它们。
答案 2 :(得分:0)
我不知道是什么让你期望UDP的丢弃率低于1%。
话虽如此,基于RFC 1122(参见section 3.3.2),保证不分成多个IP数据报的最大缓冲区大小为576字节。可以传输较大的UDP数据报,但它们很可能被分成多个IP数据报,以便在接收端重新组装。
我认为导致你所看到的丢弃数据包的高速率的一个原因是,如果一个IP数据包是大型UDP数据报的一部分,那么整个UDP数据报将会迷路了。而且你在计算UDP数据报 - 而不是IP数据包。
答案 3 :(得分:0)
您的期望,如您的问题以及对其他答案的众多评论中所表达的,都是错误的。即使没有路由器和电缆,也会发生以下所有情况。
如果您将数据包发送到任何接收器并且其套接字接收缓冲区中没有空间,它将被丢弃。
如果您发送的UDP数据报大于路径MTU,则会将其分段为较小的数据包,这些数据包受(1)的影响。
如果数据报的所有数据包都没有到达,数据报将永远不会被传递。
TCP / IP堆栈没有义务按顺序传送数据包或UDP数据报。
答案 4 :(得分:-1)
UDP数据包无法保证到达目的地,而TCP则是!