Подтвердить что ты не робот

Что может привести к удалению пакетов UDP при отправке на localhost?

Я отправляю очень большие (64000 байт) датаграммы. Я понимаю, что MTU намного меньше, чем 64000 байт (типичное значение составляет около 1500 байт, из моего чтения), но я бы заподозрил, что произойдет одна из двух вещей: либо никакие датаграммы не пройдут (все больше 1500 байт будет автоматически отключен или вызвать ошибку/исключение) или 60 000 байтовых дейтаграмм будут переданы в около 43 1500 байтовых сообщений и переданы прозрачно.

В течение длительного времени (2000+ 64000 байт-дейтаграмм) около 1% (что кажется ненормально высоким для даже локальной сети) датаграмм снижается. Я мог бы ожидать этого по сети, где дейтаграммы могут выходить из строя, отбрасываться, фильтроваться и т.д. Однако я не ожидал этого при работе на локальном хосте.

Что вызывает неспособность отправлять/получать данные локально? Я понимаю, что UDP ненадежен, но я не ожидал, что он будет настолько ненадежным на локальном хосте. Мне интересно, просто ли это проблема времени, так как отправляющие и принимающие компоненты находятся на одной машине.

Для полноты я включил код для отправки/получения дейтаграмм.

Отправка

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();
}
4b9b3361

Ответ 1

Что вызывает неспособность отправлять/получать данные локально?

В основном буферное пространство. Скажем, что вы отправляете постоянную 10 МБ/секунду, и вы можете потреблять только 5 МБ/с, операционная система и сетевой стек не могут идти в ногу со временем, поэтому они будут падать на пакеты - это должно быть довольно очевидным. (Что, естественно, отличается от TCP, который обеспечивает управление потоком и повторную передачу для обработки такой ситуации).

Даже если вы обычно не отстаете от потребления данных, могут быть небольшие срезы времени, где вы не находитесь. например собрался сборщик мусора, ОС решила запланировать другой процесс вместо вашего потребителя на 0,5 секунды и т.д. - и система отбросит пакеты.

Это может быть распространено на любые сетевые устройства между ними. Если вы работаете в сети, а не только локально, коммутатор Ethernet, маршрутизатор и т.д. Также отбрасывают пакеты, если их очереди заполнены (например, вы отправляете поток 10 МБ/с через Ethernet-коммутатор 100 МБ/с и через несколько секунд в середине ночи кто-то другой пытается перерезать 100 МБ/с по тому же пути, некоторые пакеты потеряют.)

Попробуйте увеличить размер буферов сокетов, часто вам приходится увеличивать это и на уровне ОС.

(например, в linux размер буфера сокета по умолчанию часто составляет всего 128 тыс. или меньше, что оставляет очень мало места для приостановки обработки данных, вы можете попытаться увеличить их, установив sysctl net.core.wmem_max, net.core.wmem_default, net.core.rmem_max, net.core.rmem_default)

Ответ 2

Планирование UDP pkts может обрабатываться несколькими потоками на уровне ОС. Это объясняет, почему вы получаете их не по порядку даже на 127.0.0.1.

Ответ 3

Я не знаю, что заставляет вас ожидать процент менее 1% упавших пакетов для UDP.

Как говорится, на основе RFC 1122 (см. раздел 3.3. 2), максимальный размер буфера, который не должен быть разделен на несколько IP-дейтаграмм, составляет 576 байт. Более крупные UDP-датаграммы могут быть переданы, но они, скорее всего, будут разбиты на несколько IP-датаграмм, которые будут собраны в конечной точке приема.

Я бы предположил, что причина, связанная с высокой скоростью упавших пакетов, которую вы видите, заключается в том, что если один IP-пакет, который был частью большой дейтаграммы UDP, будет потерян, вся датаграмма UDP будет потеряна. И вы считаете датаграммы UDP, а не IP-пакеты.

Ответ 4

Ваши ожидания, выраженные в вашем вопросе и в многочисленных комментариях к другим ответам, неверны. Все перечисленное может произойти даже при отсутствии маршрутизаторов и кабелей.

  • Если вы отправляете пакет в любой приемник, и нет места в буфере приема сокета, он будет сброшен.

  • Если вы отправляете дейтаграмму UDP, большую, чем MTU пути, она будет фрагментирована на более мелкие пакеты, которые подлежат (1).

  • Если все пакеты дейтаграммы не поступают, датаграмма никогда не будет доставлена.

  • Стек TCP/IP не обязан предоставлять пакеты или UDP датаграммы в порядке.

Ответ 5

UDP-пакеты не гарантированно достигают своего пункта назначения, в то время как TCP - это!