пятница, 17 октября 2008 г.

Используйте программу ttcp

Часто необходимо иметь утилиту, которая может посылать произвольный объем данных другой (или той же самой) машине по протоколу TCP или UDP и собирать статистическую информацию о полученных результатах. В этой книге уже написано несколько программ такого рода. В этом разделе вы познакомитесь с готовым инструментом, обладающим той же функциональностью. Подобное средство можно использовать для тестирования собственного приложения или для получения информации о производительности конкретного стека TCP/IP или сети. Такая информация может оказаться бесценной на этапе создания прототипа.

Этот инструмент - программа ttcp, бесплатно распространяемая Лабораторией баллистических исследований армии США (BRL - Ballistics Research Laboratory). Ее авторы Майк Муусс (автор программы ping) и Терри Слэттери. Эта утилита доступна на множестве сайтов в Internet. В книге будет использована версия, которую Джон Лин модифицировал с целью включения дополнительной статистики; ее можно получить по анонимному FTP с сайта gwen.cs.purdue.edu из каталога /pub/lin. Версия без модификаций Лина находится, например, на сайте ftp.sgi.com в каталоге sgi/ src/ttcp, в состав ее дистрибутива входит также страница руководства.

У программы ttcp есть несколько опций, позволяющих управлять: объемом посылаемых данных, длиной отдельных операций записи и считывания, размерами буферов приема и передачи сокета, включением или отключением алгоритма Нейгла и даже выравниванием буферов в памяти. На рис. приведена информация о порядке использования ttcp. Дается перевод на русский язык, хотя оригинальная программа, естественно, выводит справку по-английски.
Порядок вызова ttcp

Поэкспериментируем с размером буфера передачи сокета. Сначала прогоним тест с размером буфера, выбранным по умолчанию, чтобы получить точку отсчета. В одном окне запустим экземпляр ttcp-потребителя:

bsd: $ ttcp -rsv

а в другом - экземпляр, играющий роль источника:

bsd: $ ttcp -tsv bsd

ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5013 tcp -> bsd

ttcp-t: socket

ttcp-t: connect

ttcp-t: 16777216 bytes in 1.341030 real seconds

= 12217.474628 KB/sec (95.449021 Mb/sec)

ttcp-t: 16777216 bytes in 0.00 CPU seconds

= 16384000.000000 KB/cpu sec

ttcp-t: 2048 I/O calls, msec/call = 0.67, calls/sec = 1527.18

ttcp-t: buffer address 0x8050000

bds: $

Как видите, ttcp дает информацию о производительности. Для передачи 16 Мб потребовалось около 1,3 с.

Примечание Аналогичная статистика печатается принимающим процессом, но поскольку цифры, по существу, такие же, они здесь не приводятся.

Также был выполнен мониторинг обмена с помощью tcpdump. Вот типичная строка выдачи:

13:05:44.084576 bsd.1061 > bsd.5013: . 1:1449(1448)

ack Iwinl7376 (DF)

Из нее видно, что TCP посылает сегменты по 1448 байт. Теперь следует установить размер буфера передачи равным 1448 байт, и повторить эксперимент. Приемник данных нужно оставить без изменения.

bsd: $ ttcp -tsvb 1448 bsd

ttcp-t socket

ttcp-t sndbuf

ttcp-t connect

ttcp-t buflen=8192, nbuf=2048, align=16384/0, port=5013,

sockbufsize=1448 tcp -> bsd

ttcp-t 16777216 bytes in 2457.246699 real seconds

= 6.667625 KB/sec (0.052091 Mb/sec)

ttcp-t 16777216 bytes in 0.00 CPU seconds

= 16384000.000000 KB/cpu sec

ttcp-t 2048 I/O calls, msec/call = 1228.62, calls/sec = 0.83

ttcp-t buffer address 0x8050000

bds: $

На этот раз передача заняла почти 41 мин. Следует отметить, что, хотя по часам для передачи потребовалось больше 40 мин, время, затраченное процессором, по-прежнему очень мало, даже не поддается измерению. Поэтому, что бы ни произошло, это не связано с загрузкой процессора.





Типичная выдача tcpdump для запуска ttcp -tsvb 1448 bsd

Обратите внимание, что время между последовательными сегментами составляет почти 200 мс. Возникает подозрение, что тут замешано взаимодействие между алгоритмами Нейгла и отложенного подтверждения (совет 24). И действительно именно АСК задерживаются.

Эту гипотезу можно проверить, отключив алгоритм Нейгла с помощью опции -D. Повторим эксперимент:

bsd: $ ttcp -tsvDb 1448 bed

ttcp-t buflen=8192, nbuf=2048, align=16384/0, port=5013,

sockbufsize=1448 tcp -> bsd

ttcp-t socket

ttcp-t sndbuf ttcp-t connect

ttcp-t nodelay ttcp-t 16777216 bytes in 2457.396882 real seconds

= 6.667218 KB/sec (0.052088 Mb/sec)

ttcp-t 16777216 bytes in 0.00 CPU seconds

= 16384000.000000 KB/cpu sec

ttcp-t 2048 I/O calls, msec/call = 1228.70, calls/sec = 0.83

ttcp-t buffer address 0x8050000

bds: $


Как ни странно, ничего не изменилось.
Примечание

Это пример того, как опасно делать поспешные заключения. Стоило немного подумать и стало бы ясно, что алгоритм Нейгла тут ни при чем, так как посылаются заполненные сегменты. В частности, этому служит самый первый тест, - чтобы определить величину MSS.

В совете 39 будут рассмотрены средства трассировки системных вызовов. Тогда вы вернетесь к этому примеру и обнаружите, что выполняемая ttcp операция записи не возвращает управление в течение примерно 1,2 с. Косвенное указание на это видно и из выдачи ttcp, где каждый вызов операции ввода/вывода занимает приблизительно 1,228 мс. Но, как говорилось в совете 15, TCP обычно не блокирует операции записи, пока буфер передачи не окажется заполненным. Таким образом, становится понятно, что происходит. Когда ttcp записывает 8192 байта, ядро копирует первые 1448 байт в буфер сокета, после чего блокирует процесс, так как места в буфере больше нет. TCP посылает все эти байты в одном сегменте, но послать больше не может, так как в буфере ничего не осталось.

Примечание

Из рис. видно, что дело обстоит именно так, поскольку в каждом отправленном сегменте задан флаг PSH, а стеки, берущие начало в системе BSD, устанавливают этот флаг только тогда, когда выполненная операция передачи опустошает буфер.

Поскольку приемник данных ничего не посылает в ответ, запускается механизм отложенного подтверждения, из-за которого АСК не возвращается до истечения тайм-аута в 200 мс.

В первом тесте TCP мог продолжать посылать заполненные сегменты данных, поскольку буфер передачи был достаточно велик (16 Кб на машине bsd) для сохранения нескольких сегментов. Трассировка системных вызовов для этого теста показывает, что на операцию записи уходит около 0,3 мс.

Этот пример наглядно демонстрирует, как важно, чтобы буфер передачи отправителя был, по крайней мере, не меньше буфера приема получателя. Хотя получатель был готов принимать данные и дальше, но в выходном буфере отправителя задержался последний посланный сегмент. Забыть про него нельзя, пока не придет АСК, говорящий о том, что данные дошли до получателя. Поскольку размер одного сегмента значительно меньше, чем буфер приема (16 Кб), его получение не приводит к обновлению окна (совет 15). Поэтому АСК задерживается на 200 мс. Подробнее о размерах буферов рассказано в совете 32.

Однако смысл этого примера в том, чтобы показать, как можно использовать ttcp для проверки эффекта установки тех или иных параметров TCP-соединения. Вы также видели, как анализ информации, полученной от ttcp, tcpdump и программы трассировки системных вызовов, может объяснить работу TCP.

Следует упомянуть о том, как использовать программу ttcp для организации <сетевого конвейера> между хостами. Например, скопировать всю иерархию каталогов с хоста А на хост В. На хосте В вводите команду

ttcp -rB I tar -xpf -


на хосте А - команду

tar -cf - каталог I ttcp -t A


Можно распространить конвейер на несколько машин, если на промежуточных запустить команду

ttcp -r I ttcp -t следующий_узел


Резюме

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


Источник:

http://plasma.karelia.ru/~alexmou/net_tech/gl4.html#9

Скачать ttcp:

http://ftp.uni-koeln.de/net/performance/ttcp/ttcp.tar.gz

Комментариев нет: