2

Во время устранения проблемы, описанной здесь, я попробовал кое-что действительно простое: я попытался настроить очень простое соединение Netcat по UDP, и я заметил, что оно не работает, как я ожидал.

Как и в случае с иллюстрацией TCP, приведенной ниже, я ожидал, что случай UDP отобразит тот же вывод в окне 1, что и при наборе его в окне 2; вместо этого я не получаю вывод в окне 1 в случае UDP.

Я использую Debian Jessie на своем ноутбуке, и у меня работает Wireshark со следующим фильтром захвата:

udp and not (port 123 or port 5353 or port 1900)

В одном окне терминала я начал с теста TCP, выполнив следующую команду:

$ nc -l 6900

Во втором окне терминала я запустил следующее:

$ nc localhost 6900

В окне 2 я набрал "one" и нажал Enter, затем набрал "two" и нажал Enter, и наконец я нажал Ctrl+D для выхода.

После нажатия Enter на "один", я увидел "один" эхом в окне 1. После нажатия Enter на "два", я увидел "два" эхом в окне 1. Когда я нажал Ctrl+D, оба экземпляра netcat вышли, и я вернулся к приглашению.

Это демонстрирует, что я мог получить соединение TCP без проблем. Далее я попробовал UDP.

Окно 1:

$ nc -l -u 6900

Окно 2:

$ nc -u localhost 6900

Это забавно. Я думаю, что я мог бы только набрать "один", нажать Enter, затем "два" и нажать Enter, и я автоматически вернулся к приглашению в окне 2.

В окне 1 я не вижу никакого вывода.

Я повторил попытку с -v в окне 1:

$ nc -v -l -u 6900
Listening on [0.0.0.0] (family 0, port 6900)

Забавно, когда я повторил попытку с -v в Window 2:

$ nc -v -u localhost 6900
$

Это как netcat никогда не бежал; Я немедленно вернулся к подсказке.

Обновление: если я заменю localhost на 127.0.0.1 , прогресс будет достигнут.

С "сервером", слушающим в Окне 1:

$ nc -v -l -u 6900
one
two
three

Мне удалось получить вывод эхом из окна 2 при вводе "один", "два" и "три":

$ nc -u 127.0.0.1 6900
one
two
three
^C

-v все еще озадачивает, потому что это то же самое, что и выше.

2 ответа2

4

ТЛ; др

Смотрите выводы в самом конце.


преамбула

Я могу объяснить ваши результаты. Я использую Kubuntu, а не Debian, но все же я считаю, что основные моменты являются общими. Чтобы полностью понять, что происходит, полезно проанализировать случай TCP, а затем сравнить с UDP.

Если вы хотите повторить мое исследование, не прекращайте и не убивайте nc если я не скажу так, или это не прекратится само по себе. Убей nc s когда я скажу. Это очень важно. Прочитав полный ответ, вы поймете смысл этого.

Этот анализ требует нескольких терминалов (или tmux , или screen).


TCP чехол

Сначала избавьтесь от всех предыдущих процессов nc .

killall nc

Запустите процесс прослушивания:

nc -l 6900

Изучите вывод lsof -i :6900 . Ваш nc указан как процесс прослушивания.

Запустите процесс подключения:

nc localhost 6900

Изучите вывод lsof -i :6900 . Два nc s являются концами установленного соединения.

Поскольку ваш первый nc больше не слушает, вы можете запустить второй процесс прослушивания:

nc -l 6900

и второй процесс подключения:

nc localhost 6900

Напечатайте что-нибудь в каждой консоли, где работает nc (не забывайте нажимать Enter каждый раз). Вы заметите, что есть два отдельных соединения. Вы можете установить третий, если хотите.

Снова проверьте lsof -i :6900 . Хотя два (ранее) прослушивающих nc используют один и тот же порт 6900 , два соединения не смешиваются, потому что nc на других концах используют разные порты. Когда пакет поступает на порт 6900 , ядро проверяет этот другой порт и решает, какой из (ранее) прослушивающих nc должен его получить.

Вы можете запустить дополнительные (непарные) подключения nc:

nc localhost 6900 || echo fail

и это немедленно провалится.

У вас все еще есть два отдельных соединения. Завершите один nc каждой пары с помощью Ctrl + C или Ctrl + D, и вы заметите, что соответствующие концы также прекратятся. Это потому, что TCP ориентирован на соединение. Когда соединение изящно завершается с любого из его концов, другой конец уведомляется, чтобы он мог соответственно реагировать - в этом случае nc просто завершается.


Случай UDP

Важный:

killall nc

Выполните следующие команды последовательно, каждая в отдельной консоли. Также проверьте lsof -i :6900 после каждого, чтобы увидеть, что происходит. Команды:

nc -ul 6900
nc -u localhost 6900

Введите что-то в первый ("прослушивание") nc (нажмите Enter); проверьте lsof -i :6900 ; введите что-нибудь во второй nc (нажмите Enter); снова проверьте lsof -i :6900 и обратите внимание на изменение.

Затем подготовьте другую пару (в отдельных консолях):

nc -ul 6900
nc -u localhost 6900

Передайте несколько строк назад и вперед, чтобы увидеть, работает ли это. Завершите работу одного nc с помощью Ctrl + C (Ctrl + D не будет работать) и обратите внимание, что другой nc (на соответствующем конце) все еще работает. Другая сторона "соединения" не знает, когда "соединение" "прервано". Как вы могли видеть с lsof он не знает, что "соединение" "установлено", пока данные не начнут течь.

Я приведу здесь несколько слов, потому что UDP не имеет соединения, и в этом главное отличие.


Что может быть сложным?

Пока все должно было работать. Пришло время начать объяснять свои предыдущие результаты, когда что-то не работает.

Важный:

killall nc

Подготовьте "слушающий" nc:

nc -ul 6900

Проверьте lsof -i :6900 . Вывод будет выглядеть так:

… UDP *:6900

Подготовьте "соединительный" nc:

nc -u localhost 6900

Проверьте lsof -i :6900 . Пример вывода (ваш 54766 может отличаться):

… UDP *:6900
… UDP localhost:54766->localhost:6900

Передайте некоторые данные из второго nc в первый. Проверьте lsof -i :6900 :

… UDP localhost:6900->localhost:54766
… UDP localhost:54766->localhost:6900

Завершите второй nc с Ctrl + C. Опять lsof -i :6900

… UDP localhost:6900->localhost:54766

Это означает, что первый nc "общается" только с портом 54766 на другом конце "соединения". Когда вы пытаетесь подключиться с третьим nc:

nc -u localhost 6900

Скорее всего, он выберет другой случайный порт на своей стороне. Попытайся. Вы сможете "пропустить" (примерно) две строки, так же, как вы делали это в своем вопросе, до того, как этот nc завершится.

(Примечание: этот nc завершается из-за ICMP-пакета, посмотрите это ; вы можете захватить пакет с помощью wireshark как я.)

Однако вы можете принудительно настроить правильный порт (измените 54766 чтобы он соответствовал вашему lsof ):

nc -up 54766 localhost 6900

и этот четвертый nc сможет передавать данные! Первый nc не увидит разницы. Это будет, как если бы второй nc никогда не завершался.

Завершите четвертый nc прежде чем продолжить. Оставьте первый работающим.


Опция -v

Последняя загадка: почему nc -v -u localhost 6900 немедленно завершил работу ?

В приведенном выше примере у нас было четыре nc s:

  1. первый - "слушающий";
  2. вторая - успешно подключена, затем прекращена;
  3. третий - невозможно подключиться из-за неправильного локального порта;
  4. четвертый - возможность подключения благодаря правильному (принудительному) локальному порту.

В моем Kubuntu nc -uv … , если он второй , передает несколько символов X , вероятно, для проверки соединения. По этой причине, если он третий , ему не нужно (около) двух строк внешнего ввода для сбоя, он сразу выходит из строя. После запуска первого nc попробуйте:

nc -uv localhost 6900

Это должно потерпеть неудачу. Опять же, вы можете принудительно настроить правильный порт, и он будет работать так же, как четвертый nc в приведенном выше примере.

nc -uvp 54766 localhost 6900

Когда я вызываю это, я вижу X ы, напечатанные в консоли первого nc .


очищающий

killall nc

Выводы

Мне кажется, у вас был ("слушающий") nc который уже был связан с определенным портом на другой стороне "соединения", скорее всего из-за другого nc (или чего-то еще), который успешно передал хотя бы один пакет , Другие ваши nc пытались использовать другие порты на своей стороне и не могли связаться с этим первым.

Если я заменю localhost на 127.0.0.1 , то прогресс будет

Ненужные. Полагаю, в этом случае вы только начали чистить, как мы сделали после killall nc .

3

Используя macOS, я прихожу к другому выводу. Ключ IPv6. localhost разрешает как IPv6, так и IPv4. Однако следующая командная строка заставит nc прослушивать IPv4:

nc -l -u 6900

Результат:

$ lsof -n -i:6900
COMMAND   PID  USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
nc      63923 fuzzy    3u  IPv4 0xad7f669b928a178b      0t0  UDP *:6900

Теперь, когда вы используете это для «подключения»:

nc -u localhost 6900

... это на самом деле подключается к IPv6. Когда вы используете 127.0.0.1 это не так.

Однако он не подключается, потому что UDP не подключен. Таким образом, нет способа узнать, существует ли действительно удаленный конец соединения. Таким образом, он не может обнаружить, что должен вернуться к IPv4. Ваши сообщения будут отправлены, но ничего не прослушивается.

При отправке можно наблюдать следующее:

$ tcpdump -i lo0 udp port 6900
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
00:46:37.543273 IP6 localhost.54473 > localhost.6900: UDP, length 6

С помощью TCP он попытается подключиться по IPv6, определит, что это не работает, и повторите попытку с IPv4:

$ tcpdump -i lo0 port 6900
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
00:50:21.495107 IP6 localhost.64306 > localhost.6900: Flags [SEW], seq 1432891337, win 65535, options [mss 16324,nop,wscale 5,nop,nop,TS val 766376063 ecr 0,sackOK,eol], length 0
00:50:21.495136 IP6 localhost.6900 > localhost.64306: Flags [R.], seq 0, ack 1432891338, win 0, length 0
00:50:21.495231 IP localhost.64307 > localhost.6900: Flags [S], seq 307818799, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 766376063 ecr 0,sackOK,eol], length 0
00:50:21.495283 IP localhost.6900 > localhost.64307: Flags [S.], seq 4254625238, ack 307818800, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 766376063 ecr 766376063,sackOK,eol], length 0
00:50:21.495295 IP localhost.64307 > localhost.6900: Flags [.], ack 1, win 12759, options [nop,nop,TS val 766376063 ecr 766376063], length 0
00:50:21.495306 IP localhost.6900 > localhost.64307: Flags [.], ack 1, win 12759, options [nop,nop,TS val 766376063 ecr 766376063], length 0

Вы можете заставить nc использовать IPv4:

nc -4u localhost 6900

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .