Захват связи между сервером и клиентом с помощью tcpdump

Я написал простые серверные и клиентские приложения, в которых я могу переключаться между протоколами TCP, DCCP и UDP. Цель состояла в том, чтобы передать файл из одного в другой и измерить трафик для каждого протокола, чтобы я мог сравнить их для разных настроек сети (я примерно знаю, какой должен быть результат, но мне нужны точные цифры/графики). В любом случае, после запуска обоих приложений на разных компьютерах и запуска tcpdump я получаю в журнале tcpdump только первые несколько МБ (~ 50 МБ) из моего файла размером 4 ГБ. Приложения написаны на стандартном коде C/C++, который можно найти где угодно в Интернете. В чем может быть проблема или что я могу делать неправильно здесь?

-- Изменить

Командная строка, которую я использую:

tcpdump -s 1500 -w mylog

tcpdump захватывает, а затем отправляет пакеты только первые ~55 секунд. Это время, необходимое клиенту для отправки файла в сокет. После этого он останавливается, хотя сервер продолжает получать и записывать файл на жесткий диск.

-- Редактировать2

Исходный код:

client.cpp
server.cpp
common.hpp
common.cpp

-- Редактировать финал

Как многие из вас указывали (и как я подозревал), в исходном коде было несколько неправильных представлений/ошибок. После того, как я его почистил (или почти переписал), с tcpdump работает как надо. Я приму ответ от @Laurent Parenteau, но только для пункта 5, поскольку он был единственным, имеющим отношение к проблеме. Если кого-то интересует правильный код, вот он:

Исходный код изменен

client.cpp
server.cpp
common.hpp
common.cpp


person stefita    schedule 27.07.2010    source источник
comment
по умолчанию tcpdump захватывает только первые несколько байтов в каждом пакете. Вы приказали ему захватить все, используя параметр -s snaplen?   -  person nos    schedule 27.07.2010
comment
@nos, спасибо! Я попробовал это, но все еще не повезло. Смотрите мою правку.   -  person stefita    schedule 27.07.2010
comment
Можете ли вы опубликовать команду tcpdump, используемую для захвата сетевого трафика?   -  person Laurent Parenteau    schedule 27.07.2010
comment
@Laurent Parenteau: tcpdump -s 1500 -w mylog   -  person stefita    schedule 28.07.2010
comment
Вы убедились, что передача прошла успешно? Вы можете сравнить md5sum исходного файла и полученного файла, чтобы убедиться в этом.   -  person Laurent Parenteau    schedule 29.07.2010
comment
@Laurent Parenteau: да, файл был получен на 100% с другой стороны.   -  person stefita    schedule 30.07.2010
comment
Где вы выполняете захват? На промежуточном хосте? На одном из хостов?   -  person ereOn    schedule 30.07.2010
comment
@ereOn: как на сервере, так и на клиенте, и оба прекращают ведение журнала через одинаковое количество времени.   -  person stefita    schedule 30.07.2010
comment
Тег 'c' следует удалить, так как ваш код написан на C++, а не на C.   -  person Laurent Parenteau    schedule 30.07.2010
comment
В последнем абзаце вы заявляете, что сервер продолжает получать даже после того, как клиент перестанет отправлять. Если клиент ничего не отправляет, то что он получает?   -  person torak    schedule 30.07.2010
comment
@torak: на самом деле это мой вопрос. Файл растет на сервере, хотя клиентское приложение уже завершило отправку и завершило работу. Как я уже сказал, на моей стороне может быть общая утечка знаний.   -  person stefita    schedule 30.07.2010
comment
Ну, это может быть настолько просто, что вы можете завершить передачу по сети быстрее, чем файл может быть записан на диск. С передачей 4 ГБ и передачей 55 секунд вы немного превышаете максимальную скорость передачи, которую предлагает Википедия, примерно 70 мегабайт в секунду. См. en.wikipedia.org/wiki/Hard_disk_drive. Однако, даже принимая во внимание буферизацию на уровне сокета и файлового ввода-вывода, было бы натяжкой думать, что это объясняет ~ 50 МБ, записанных через 55 секунд.   -  person torak    schedule 30.07.2010
comment
В рассматриваемом коде так много проблем (я могу назвать по крайней мере 3 из беглого изучения), что я сильно подозреваю, что наблюдаемое поведение является результатом ошибок различных разновидностей. Я запускал tcpdump в течение нескольких дней, и он по-прежнему добросовестно собирал данные, о которых я его просил. Я подозреваю, что сервер записывает на диск данные, которые он на самом деле не получал из сети, и поэтому для него нет сетевого трафика.   -  person Omnifarious    schedule 03.08.2010


Ответы (5)


В коде много неправильного.

  1. Размер файла/размер передачи жестко запрограммирован на 4294967295 байт. Итак, если предоставленный файл не так много байтов, у вас будут проблемы.
  2. В отправителе вы не проверяете, успешно ли прочитано файл или нет. Таким образом, если файл меньше 4294967295 байт, вы не узнаете об этом и отправите ненужные данные (или вообще ничего) по сети.
  3. Когда вы используете UDP и DDCP, порядок пакетов не гарантируется, поэтому полученные данные могут быть не в порядке (т.е. мусор).
  4. При использовании UDP повторная передача потерянного пакета невозможна, поэтому некоторые данные могут никогда не быть получены.
  5. В приемнике вы не проверяете, сколько байт вы получили, вы всегда записываете MAX_LINE байт в файл. Таким образом, даже если вы получите 0 байт, вы все равно будете писать в файл, что неверно.
  6. Когда вы используете UDP, поскольку вы отправляете в цикле бедра, даже если вызов write() возвращает то же количество отправленных байтов, что и запрошенный вами, много данных, вероятно, будет удалено сетевым стеком или сетевым интерфейсом. , так как отсутствует контроль перегрузки. Таким образом, вам нужно будет установить контроль за перегрузкой самостоятельно.

И это только из беглого просмотра кода, там наверняка больше проблем...

Мое предложение: попробуйте передать с помощью TCP, выполните md5sum файла, который вы читаете/отправляете, и md5sum файла, который вы получаете/сохраняете, и сравните 2 md5sum. Как только этот случай заработает, вы можете перейти к тестированию (по-прежнему используя сравнение md5sum) с UDP и DCCP...

Для команды tcpdump вы должны изменить -s 1500 на -s 0, что означает unlimited. С помощью этой команды tcpdump вы можете доверять ей, что данные, которые она не видела, не были отправлены/получены. Еще одна хорошая вещь — сравнить вывод tcpdump отправителя с получателем. Таким образом, вы узнаете, произошла ли потеря какого-либо пакета между двумя сетевыми стеками.

person Laurent Parenteau    schedule 30.07.2010
comment
1. и 2. разумны, но они предназначены только для целей тестирования и сохраняют компактность исходного кода. 3., 4. и 6. также известны, целью тестов является не реализация приложения надежной передачи, а проверка производительности протокола (в основном пропускной способности). 5. хороший момент, я изменю это. Я уже пробовал тесты с TCP, и файл поступает нормально, и независимо от того, какое значение я установил для snaplen, tcp не будет записываться за ~ 55 секунд. - person stefita; 30.07.2010
comment
И как долго после этого приемник еще принимает данные? Я спрашиваю, так как данные вполне могут быть получены, но все еще в буферах стека (еще не прочитаны приложением). Это может объяснить небольшую разницу между временем передачи по сети и временем, которое требуется, чтобы прочитать все в приложении и записать это в файл. - person Laurent Parenteau; 30.07.2010
comment
для записи остальной части файла на диск требуется больше минуты. tcpdump фиксирует только часть сообщений. Если я запускаю ftp-передачу, она захватывает все пакеты... - person stefita; 30.07.2010
comment
Что касается вашего предыдущего комментария, целью тестов является не реализация надежного приложения для передачи, а проверка производительности протокола (в основном пропускной способности). Если у вас много отбрасываемых пакетов, производительность будет казаться лучше, чем она есть на самом деле. Если, конечно, конечное приложение не заботится об отбрасывании пакетов и надежной связи... - person Laurent Parenteau; 30.07.2010
comment
Что касается суммы md5 отправленного и полученного файла... Является ли этот файл повторяющимся шаблоном или в основном случайными данными? - person Laurent Parenteau; 30.07.2010
comment
@stefita - tcpdump перехватывает все отправляемые пакеты. Многочисленные ошибки в вашем коде скрывают тот факт, что он в значительной степени не отправляет большую часть данных, которые, как вы думаете, он отправляет. Получатель, кажется, продолжает «получать», потому что ошибки в вашем коде заставляют его записывать данные в файл, даже если он их не получает. tcpdump работает отлично. - person Omnifarious; 04.08.2010

У вас есть доступ на x срок? Вместо этого переключитесь на Wireshark и попробуйте с ним — он бесплатный, с открытым исходным кодом и, вероятно, сегодня более широко используется, чем tcpdump. (Ранее он был известен как Эфирный.)

Кроме того, попробуйте следующие параметры tcpdump:

  • -xx также распечатать заголовок ссылки и данные пакета (записывает ли -w данные?)
  • -C указать максимальный размер файла явно.
  • -U для записи пакета за пакетом в файл вместо очистки буфера.
  • -p не переводить сетевую карту в неразборчивый режим
  • -O не используйте оптимизатор сопоставления пакетов, так как у вас новый протокол уровня приложения.
  • Используете ли вы подробный вывод в tcpdump? Это может привести к быстрому заполнению буферов, поэтому при запуске перенаправляйте stdout/err в файл.

Это гигабитная сетевая карта на обоих концах?

person carlsborg    schedule 01.08.2010
comment
Wireshark также использует tcpdump/libpcap, так что это не имеет никакого значения. - person stefita; 02.08.2010
comment
Что ж, libpcap — это библиотека захвата пакетов, а tcpdump и wireshark — два разных приложения, которые ее используют. Я предполагаю, что это проблема на уровне приложения или конфигурации, а не в библиотеке. - person carlsborg; 02.08.2010
comment
@stefita: не будет или нет? Вы пробовали? - person Default; 04.08.2010

tcpdump используется в качестве инструмента диагностики и криминалистики десятками тысяч (как минимум) программистов и специалистов по компьютерной безопасности по всему миру. Когда кажется, что такой инструмент неправильно справляется с очень распространенной задачей, первое, что следует заподозрить, это код, который вы написали, а не инструмент.

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

Этот код имеет условия гонки, которые в некоторых ситуациях приводят к недетерминированному поведению, неправильно обрабатывает '\0' как особое значение в сетевых данных, игнорирует условия ошибки и игнорирует условия конца файла. И это только краткое чтение.

В этом случае я почти уверен, что tcpdump работает отлично и сообщает вам, что ваше приложение не делает то, что вы думаете.

person Omnifarious    schedule 04.08.2010

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

Это звучит очень странно. Буферы сокетов слишком малы, чтобы это могло произойти. Я действительно думаю, что ваш код сервера только кажется, что получает данные, в то время как отправитель фактически уже прекратил отправку данных.

person IanH    schedule 04.08.2010

Я знаю, это может звучать глупо, но вы уверены, что это не проблема flush() файла? т.е. данные все еще находятся в памяти и еще не записаны на диск (поскольку их недостаточно).

Попробуйте sync или просто подождите немного, пока не убедитесь, что передано достаточно данных.

person lorenzog    schedule 03.08.2010