2017-02-17 23 views
0

Когда я отправлял небольшие данные (16 байт и 128 байт) непрерывно (используйте 100-часовой цикл без какой-либо вставленной задержки), пропускная способность настройки TCP_NODELAY кажется не такой хорошей, как нормальная настройка. Кроме того, TCP-slow-start, по-видимому, повлиял на передачу в начале.Почему скорость TCP/IP зависит от размера отправки данных?

enter image description here

enter image description here

Причина заключается в том, что я хочу, чтобы управлять устройством с ПК через Ethernet. Время обработки этого устройства составляет около нескольких микросекунд, но огромная латентность отправки команды повлияла на всю систему. Не могли бы вы поделиться со мной некоторыми способами решения этой проблемы? Заранее спасибо.

В прошлый раз я измерил производительность передачи между Windows-ПК и встроенной линией для Linux. Чтобы проверить TCP_NODELAY, я настраиваю систему с двумя Linux-ПК, напрямую связанными друг с другом, то есть Linux PC < -> Маршрутизатор < -> Linux PC. Маршрутизатор использовался только для двух ПК.

Производительность без TCP_NODELAY показана следующим образом. Легко видеть, что пропускная способность значительно увеличилась при размере данных> = 64 КБ. Кроме того, когда размер данных = 16 B, иногда полученное время падает до 4.2 us. Есть ли у вас какое-либо представление об этом наблюдении?

enter image description here

Производительность с TCP_NODELAY кажется неизменным, как показано ниже.

enter image description here

Полный код можно найти в https://www.dropbox.com/s/bupcd9yws5m5hfs/tcpip_code.zip?dl=0

Пожалуйста, поделитесь со мной своим мышлением. Заранее спасибо.


Я занимаюсь программированием сокетов для передачи двоичного файла между ПК с Windows 10 и встроенной линией для Linux. Библиотека сокетов - winsock2.h и sys/socket.h для Windows и Linux, соответственно. Двоичный файл копируется в массив в Windows перед отправкой, а полученные данные хранятся в массиве в Linux.

Windows: socket_send (sockfd, & SOPF-> array [0], n);

Linux: socket_recv (& SOPF-> array [0], connfd);

Я мог бы получить все данные должным образом. Однако мне кажется, что время передачи зависит от размера отправляемых данных. Когда размер данных мал, полученная пропускная способность довольно низкая, как показано ниже.

enter image description here

могли бы вы показали мне некоторые документы, объясняющие эту проблему? Заранее спасибо.


+0

Принимаете ли вы с накладными пакетами? При переносе между двумя непрерывными устройствами (т. Е. С низкой вероятностью проблем с NW), чем больше буфер, тем лучше. Когда передача происходит между удаленными устройствами, ошибки и повторные передачи выходят на сцену, и, следовательно, вам необходимо уменьшить размер буфера до оптимального значения. – FDavidov

+0

Упрощенно указано, что для отправки одного пакета есть некоторые фиксированные накладные расходы. Таким образом, при меньших размерах данных вы платите за фиксированные накладные расходы намного больше, чем при большем размере данных. – kaylum

+0

TCP/IP также имеет функцию «медленный старт», которая дросселирует скорость, когда соединение «разогревается». Это повышает стабильность соединения на первых этапах соединения и снижает общий сетевой трафик по отношению к «потерянным» пакетам. – Myst

ответ

1

Сокеты TCP обычно имеют внутренний размер буфера. Во многих реализациях он будет ждать немного времени перед отправкой пакета, чтобы проверить, может ли он заполнить оставшееся пространство в буфере перед отправкой. Это называется Nagle's algorithm.Я предполагаю, что время, о котором вы сообщаете выше, происходит не из-за накладных расходов в TCP-пакете, а из-за того, что TCP ждет вас, чтобы поставить в очередь больше данных до фактической отправки.

Большинство реализаций сокетов имеют параметр или функцию, называемую как TcpNoDelay, которая может быть ложной (по умолчанию) или истинной. Я бы попробовал возиться с этим и посмотреть, влияет ли это на вашу пропускную способность. По сути эти флаги будут включать/отключать алгоритм Нагле.

+1

Это более известный как [алгоритм Нагле для коллажирования отправки] (https://en.m.wikipedia.org/wiki/Nagle's_algorithm) –

+0

Да. Я должен был положить это в сообщение. Обновление сейчас. –

+0

Благодарим вас за ответ. Я скоро проверю TCP_NODELAY. –

3

Чтобы установить соединение tcp, вам потребуется 3-стороннее рукопожатие: SYN, SYN-ACK, ACK. Затем отправитель начнет отправлять некоторые данные. Сколько зависит от начального окна перегрузки (настраивается на Linux, не знаю в окнах). Пока отправитель получает своевременные ACK, он будет продолжать отправлять, пока разрешенное окно получателей имеет пространство (используйте параметр сокета SO_RCVBUF для установки). Наконец, для закрытия соединения также требуются FIN, FIN-ACK, ACK.

Таким образом, мое лучшее предположение без дополнительной информации заключается в том, что накладные расходы на настройку и разрывание TCP-соединения оказывают огромное влияние на накладные расходы при отправке небольшого количества байтов. Алгоритм Нагле (отключенный с помощью TCP_NODELAY) не должен сильно влиять, пока писатель эффективно пишет быстро. Он предотвращает передачу менее полных сегментов MSS, что должно повысить эффективность передачи в этом случае, когда отправитель просто отправляет данные как можно быстрее. Единственный эффект, который я вижу, заключается в том, что для конечного менее полного сегмента MSS может потребоваться дождаться ACK, что снова будет иметь большее влияние на короткие передачи по сравнению с более длинными передачами.

Чтобы проиллюстрировать это, я послал один байт с помощью Netcat (nc) на моем петлевой интерфейс (который не является физическим интерфейсом, и, следовательно, пропускная способность «бесконечное»):

$ nc -l 127.0.0.1 8888 >/dev/null & 
[1] 13286 
$ head -c 1 /dev/zero | nc 127.0.0.1 8888 >/dev/null 

И вот сеть захвата в Wireshark:

enter image description here

потребовалось в общей сложности 237 микросекунд послать один байт, который является ничтожные 4.2KB/второй. Я думаю, вы можете догадаться, что если бы я отправил 2 байта, для эффективной скорости 8,2 КБ/с, на 100% улучшение получило бы такое же количество времени!

Лучший способ диагностики проблем производительности в сетях - получить сетевой захват и проанализировать его.

+0

Кажется, что вы говорите о «окне TCP», но называете это «окном перегрузки» - мне это непонятно. Кроме того, стоит ваше последнее предложение: лучший способ диагностики - проанализировать трафик. – linuxfan

+0

@linuxfan есть окно приема, которое рекламируется получателем. Отправитель не отправит больше данных, которые рекламируются получателем. Приемник может увеличить это, чтобы позволить отправлять больше данных, если оно «медленное» при обработке данных. Окно перегрузки поддерживается отправителем и относится к тому, сколько данных отправитель отправит без ACK. Начальное окно перегрузки - это то, сколько данных отправитель отправит без ACK во время медленного запуска и будет конфигурироваться по всей стране в linux. Вы можете увеличить размер, чтобы позволить запуску отправлять больше данных. –

+0

Нет, это не совсем так - особенно, окно приемника не должно увеличиваться, если приемник «работает медленно»; большое окно приемника хорош, чтобы побеждать задержки, которые всегда присутствуют. – linuxfan

1

Когда вы проводите тест с значительным количеством данных, например, ваш более крупный тест (512Mib, 536 миллионов байт), происходит следующее.

Данные отправляются по уровню TCP, разбивая их на сегментов определенной длины. Пусть предполагают сегменты 1460 байт, поэтому будет около 367 000 сегментов.

Для каждого переданного сегмента есть служебные данные (данные управления и управления добавлены для обеспечения хорошей передачи): в вашей настройке для протокола TCP, 20 для IP и 20 для ethernet имеется 20 байт, в общей сложности 56 байт все сегменты. Обратите внимание, что это номер минимум, не считая, например, преамбулы ethernet; кроме того, иногда накладные расходы IP и TCP могут быть больше, поскольку дополнительные поля.

Ну, 56 байтов для каждого сегмента (367 000 сегментов!) Означает, что при передаче 512Mib вы также передаете 56 * 367 000 = 20 Мбайт в строке. Общее количество байтов составляет 536 + 20 = 556 миллионов байт или 4 448 миллионов бит. Если вы разделите это количество бит на время, прошедшее, 4.6 секунд, вы получаете бит 966 мегабит в секунду, что выше, чем вы рассчитывали, не принимая во внимание накладные расходы.

Из приведенного выше исчисления кажется, что ваш ethernet является гигабитным . Максимальная скорость передачи данных должна составлять 1000 мегабит в секунду, и вы действительно приближаетесь к ней. В остальное время из-за большего количества накладных расходов мы не учитывали и некоторые задержки, которые всегда присутствуют и, как правило, отменяются по мере передачи большего количества данных (но они никогда не будут полностью побеждены).

Я бы сказал, что ваша настройка в порядке. А вот для больших объемов данных. Поскольку размер передачи уменьшается, накладные расходы в данных, задержки протокола и другие приятные вещи становятся все более важными. Например, если вы передаете 16 байт за 165 микросекунд (первый из ваших тестов), результат равен 0,78 Мбит/с; если бы это взяло 4.2 нас, примерно в 40 раз меньше, битрайт был бы около 31 Мбит/с (в 40 раз больше). Эти цифры ниже ожидаемых.

В действительности вы не передаете 16 байтов, вы передаете не менее 16 + 56 = 72 байта, что в 4,5 раза больше, поэтому реальная скорость передачи ссылки также больше. Но, видите ли, передача 16 байтов по каналу TCP/IP такая же, как измерение расхода пустого acqueduct путем падения в нем слез воды: слезы теряются, прежде чем они достигнут другого конца. Это связано с тем, что TCP/IP и ethernet предназначены для переноса гораздо большего количества данных с надежностью.

Комментарии и ответы на этой странице указывают на многие из этих механизмов, которые торгуют битрейтом и реактивностью для надежности: трехстороннее TCP-рукопожатие, алгоритм Нагле, контрольные суммы и другие накладные расходы и т. Д.

Учитывая дизайн TCP + IP и ethernet, очень нормально, что для небольших данных производительность не оптимальна. Из ваших тестов вы видите, что скорость передачи резко возрастает, когда размер данных достигает 64 Кбайт. Это не случайность.

Из комментария, который вы оставили выше, кажется, что вы ищете связь с низкой задержкой, а не с большой пропускной способностью. Это распространенная ошибка, чтобы запутать разные виды выступлений. Более того, в связи с этим я должен сказать, что TCP/IP и ethernet полностью недетерминированные. Конечно, они быстрые, но никто не может сказать, сколько из-за слишком много слоев между ними. Даже в вашей простой настройке, если один пакет потерян или поврежден, вы можете ожидать задержки секунд, а не микросекунды.

Если вы действительно хотите что-то с низкой задержкой, вы должны использовать что-то еще, например CAN. Его дизайн - именно то, что вам нужно: он передает небольшие данные с высокой скоростью, низкой задержкой, детерминированным временем (всего через микросекунды после того, как вы передали пакет, вы знаете, если он был получен или нет. Точнее: точно на конец передачи пакета вы знаете, если он достиг цели или нет).

+0

Благодарим вас за ответ. Это помогает. –

+0

кстати, 0.096 находится в MBytes/s и 0.78 находится в Мбит/с. –

+0

@ThuanN. Вы правы, спасибо, что указали это - я исправил свой пост соответственно. – linuxfan