什么会导致 UDP 数据包在发送到本地主机时被丢弃?概述总结延伸阅读

2022-09-01 13:12:26

我正在发送非常大的(64000字节)数据报。我意识到MTU比64000字节小得多(从我的阅读来看,典型值约为1500字节),但我怀疑会发生以下两种情况之一 - 要么没有数据报能够通过(大于1500字节的所有内容都会被静默丢弃或导致抛出错误/异常),要么64000字节的数据报将被分块为大约43 1500字节的消息并透明地传输。

从长远来看(2000+ 64000字节数据报),大约1%的数据报(即使是LAN似乎异常高)的数据报都会被丢弃。我可能期望通过网络来实现这一点,其中数据报可以无序到达,被丢弃,过滤等等。但是,在本地主机上运行时,我没想到会这样。

是什么原因导致无法在本地发送/接收数据?我意识到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();
}

答案 1

概述

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

主要是缓冲空间。想象一下,发送恒定的10MB /秒,而只能消耗5MB /秒。操作系统和网络堆栈跟不上,因此数据包被丢弃。(这与TCP不同,TCP提供流控制和重新传输来处理这种情况。

即使使用的数据没有溢出缓冲区,也可能有一小部分时间片无法消耗数据,因此系统将丢弃数据包。(例如,在垃圾回收期间,或者当操作系统任务暂时切换到更高优先级的进程时,等等。

这适用于网络堆栈中的所有设备。当队列已满时,非本地网络、以太网交换机、路由器、集线器和其他硬件也会丢弃数据包。通过 100MB/s 以太网交换机发送 10MB/s 的流,而其他人尝试通过同一物理线路将 100MB/s 的流放入,将导致数据包丢失。

增加套接字缓冲区大小和操作系统的套接字缓冲区大小。

Linux

默认套接字缓冲区大小通常为 128k 或更小,这为暂停数据处理留出的空间非常小。

系统

使用 sysctl 增加传输(写入内存 [wmem])和接收(读取内存 [rmem])缓冲区:

  • net.core.wmem_max
  • net.core.wmem_default
  • net.core.rmem_max
  • net.core.rmem_default

例如,要将值提高到 8 MB:

sysctl -w net.core.rmem_max=8388608

要使设置保持不变,请同时进行更新,例如:/etc/sysctl.conf

net.core.rmem_max=8388608

一篇关于调整网络堆栈的深入文章深入探讨了更多细节,涉及了如何在Linux中接收和处理数据包的多个级别,从内核的网络驱动程序到环形缓冲区一直到C的调用。本文介绍了诊断网络问题时要监视的其他设置和文件。(见下文。recv

在进行以下任何调整之前,请务必了解它们如何影响网络堆栈。确实有可能使您的网络无法使用。选择适合您的系统、网络配置和预期流量负载的号码:

  • net.core.rmem_max=8388608
  • net.core.rmem_default=8388608
  • net.core.wmem_max=8388608
  • net.core.wmem_default=8388608
  • net.ipv4.udp_mem='262144 327680 434274'
  • net.ipv4.udp_rmem_min=16384
  • net.ipv4.udp_wmem_min=16384
  • net.core.netdev_budget=600
  • net.ipv4.ip_early_demux=0
  • net.core.netdev_max_backlog=3000

乙状体

此外,对于查询或更改网络设置也很有用。例如,如果 是(使用或确定您的网络设备名称),则可以使用以下方法增加 RX 和 TX 缓冲区:ethtool${DEVICE}eth0ip addressipconfig

  • ethtool -G ${DEVICE} rx 4096
  • ethtool -G ${DEVICE} tx 4096

iptables

默认情况下,将记录有关数据包的信息,这会消耗 CPU 时间,尽管时间极短。例如,您可以使用以下命令在端口 6004 上禁用 UDP 数据包的日志记录:iptables

iptables -t raw -I PREROUTING 1 -p udp --dport 6004 -j NOTRACK
iptables -I INPUT 1 -p udp --dport 6004 -j ACCEPT

您的特定端口和协议会有所不同。

监测

多个文件包含有关在发送和接收的各个阶段网络数据包发生的情况的信息。以下列表中是中断请求编号,是网络设备:${IRQ}${DEVICE}

  • /proc/cpuinfo- 显示可用的CPU数量(有助于IRQ平衡)
  • /proc/irq/${IRQ}/smp-affinity- 显示 IRQ 亲和力
  • /proc/net/dev- 包含一般数据包统计信息
  • /sys/class/net/${DEVICE}/queues/QUEUE/rps_cpus- 与接收数据包控制 (RPS) 相关
  • /proc/softirqs- 用于 ntuple 过滤
  • /proc/net/softnet_stat- 用于数据包统计信息,例如丢弃、时间挤压、CPU 冲突等。
  • /proc/sys/net/core/flow_limit_cpu_bitmap- 显示数据包流(可以帮助诊断大流量和小流量之间的下降)
  • /proc/net/snmp
  • /proc/net/udp

总结

缓冲区空间是丢弃数据包的最可能罪魁祸首。整个网络堆栈中散布着许多缓冲区,每个缓冲区对发送和接收数据包都有自己的影响。网络驱动程序、操作系统、内核设置和其他因素可能会影响数据包丢弃。没有银弹。

延伸阅读


答案 2

UDP pkts 调度可以由操作系统级别的多个线程处理。这可以解释为什么即使在127.0.0.1上您也会无序收到它们。


推荐