Странное поведение Netcat

Вопрос или проблема

Я пытаюсь отладить проблемы с подключением в своей домашней сети. Для этого я использую Netcat, чтобы выяснить, могут ли две машины взаимодействовать друг с другом по UDP на определенном порту.

На стороне приемника я использую

sudo nc -ul <порт>

а на стороне отправителя

echo "сообщение" | nc -u <hostname-получателя> <порт>

Происходит следующее

  • Приемник отображает “сообщение”
  • Отправитель никогда не завершает команду nc, просто зависает
  • Я выхожу из команды отправки (Ctrl-C)
  • Я отправляю другое сообщение
  • Приемник не получает это сообщение
  • Отправитель не зависает и сразу завершает работу
  • Я завершаю команду прослушивания на приемнике и запускаю ее снова
  • Цикл повторяется

В итоге, при “nc listen” я могу передать ровно одно сообщение. Команда отправки не выходит, если сообщение получено.

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

Похоже, что либо есть странная ошибка, либо я фундаментально неправильно понимаю, как это должно работать. Можете кто-нибудь помочь мне?

Хотя UDP является протоколом без соединений, UDP сокет все же может быть “подключен” — что не генерирует сообщений, но все же имеет тот же эффект связывания сокета с определенным удаленным адресом:портом на уровне ОС.

После вызова connect() вызов recv() будет доставлять датаграммы только от указанного отправителя в программу, и наоборот, программа также может вызывать send() на этом сокете, не указывая получателя (в отличие от использования recvfrom() / sendto() на несоединенном сокете).

Ваша реализация nc вызывает connect() после получения первого пакета, чтобы “зафиксироваться” на этом конкретном потоке, в то время как сторона отправки будет создавать новый сокет и, следовательно, выбирать другой номер исходного порта каждый раз, когда вы его перезапускаете.

Чтобы достичь желаемого, вам, вероятно, нужно использовать socat udp-recvfrom:[...] (не udp-recv), хотя вы можете попробовать nc -u -p 12345 <dst> <порт>, чтобы заставить каждый процесс отправителя связываться с одним и тем же локальным (исходным) портом каждый раз.

Ответ или решение

Конечно! Давайте разберем вашу проблему с использованием Netcat для отладки соединений по UDP, и я объясню, как можно решить возникшие у вас трудности.

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

Основная Проблема

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

Когда этот вызов выполняется, сокет "привязывается" к определенному адресату, и оказывается, что последующие сообщения, отправленные из другого источника или с использованием другого порта, не принимаются, так как они не соответствуют этому "закреплённому" соединению.

Решение Проблемы

Чтобы обойти эту проблему и обеспечить правильную работу с UDP-сообщениями, вы можете попробовать следующее:

  1. Использование socat:
    Вместо nc вы можете использовать socat, который обеспечивает более гибкие параметры для работы с UDP. Для получения сообщений вы можете использовать следующую команду на стороне получателя:

    socat - UDP-LISTEN:<port>,bind=<receiver-ip>

    На стороне отправителя отправляйте сообщения так:

    echo "message" | socat - UDP:<receiver-ip>:<port>
  2. Фиксация порта для отправителя в nc:
    Если вы все же хотите использовать nc, вы можете попытаться установить один и тот же локальный порт для отправителя при каждой отправке:

    echo "message" | nc -u -p <local-port> <receiver-ip> <port>

    Убедитесь, что <local-port> остается постоянным для каждого запуска команды.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...