Вопрос или проблема
Я пытаюсь отладить проблемы с подключением в своей домашней сети. Для этого я использую 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-сообщениями, вы можете попробовать следующее:
-
Использование
socat
:
Вместоnc
вы можете использоватьsocat
, который обеспечивает более гибкие параметры для работы с UDP. Для получения сообщений вы можете использовать следующую команду на стороне получателя:socat - UDP-LISTEN:<port>,bind=<receiver-ip>
На стороне отправителя отправляйте сообщения так:
echo "message" | socat - UDP:<receiver-ip>:<port>
-
Фиксация порта для отправителя в
nc
:
Если вы все же хотите использоватьnc
, вы можете попытаться установить один и тот же локальный порт для отправителя при каждой отправке:echo "message" | nc -u -p <local-port> <receiver-ip> <port>
Убедитесь, что
<local-port>
остается постоянным для каждого запуска команды.
Заключение
Таким образом, вы можете достичь ожидаемого поведения и отправлять несколько сообщений, не сталкиваясь с проблемами, описанными вами. Использование socat
предоставляет более надежный способ работы, особенно для отладки и тестирования UDP-соединений. Попробуйте предложенные решения, и если возникнут дополнительные вопросы, не стесняйтесь спрашивать!