Я инженер-программист, проектирующий распределенное программное обеспечение, в котором процедура запуска использует многоадресную рассылку IP для обнаружения своих партнеров. Само программное обеспечение распространяется в виде различных исполняемых модулей, и поэтому иногда имеет смысл запускать несколько исполняемых модулей на одном хосте. Вот тут-то и начинаются мои проблемы, так как мне кажется, что Windows не очень хорошо справляется с управлением несколькими процессами, подписывающимися на одну многоадресную группу.
Моя цель — иметь возможность свободно выбирать, на каких хостах запускать те или иные исполняемые файлы, и они будут обнаруживать всех своих коллег (будь то на том же хосте или на других хостах) без каких-либо предопределенных знаний.
На данный момент устранение неполадок показывает, что проблема заключается в том, как Windows обрабатывает сценарий, когда несколько процессов подписываются на одни и те же многоадресные группы, по следующим причинам:
Если один и тот же процесс используется для отправки и получения многоадресных датаграмм на одной и той же машине, он работает так, как и ожидалось. Процесс можно разделить на несколько потоков без каких-либо проблем.
Если я запускаю разные процессы для отправки и получения, то принимающий процесс ничего не получает, несмотря на сообщение о присоединении к группе и все датаграммы отображаются в Wireshark.
Сценарий, описанный в пункте 2, работает, если я перед прослушиванием также использую тот же сокет для отправки пакета в группу многоадресной рассылки, к которой я присоединился. Затем последняя получает многоадресные датаграммы в течение неопределенного периода времени, после чего просто прекращает прием датаграмм (она продолжает ждать поступления датаграмм). Датаграммы подтверждаются отправленными в/из сети с помощью Wireshark.
Мои последние результаты показывают, что если я периодически отправляю многоадресное сообщение группе, на которую я подписан, я получаю датаграммы, отправленные в эту многоадресную группу, также от других процессов на том же хосте.
Насколько я понимаю, многоадресная передача IP определяет только связь междухозяева, в то время как ОС несет ответственность за перенаправление входящих пакетов в соответствующийприложение. Поскольку пакеты всегда отображаются в Wireshark, даже если приложение их не получает, похоже, что Windows не справляется с обработкой входящих пакетов или, по крайней мере, с доставкой их соответствующим приложениям.
Я признателен, если кто-нибудь сможет подтвердить или опровергнуть мои доводы, а также указать мне правильное направление решения этой проблемы. Цель состоит в том, чтобы иметь возможность для нескольких приложений на одном хосте присоединиться к одному каналу многоадресной группы и также получать сообщения без необходимости отправлять "мусор" в многоадресную группу, чтобы они могли получать данные (обходной путь, описанный как пункт номер 4).
Я использую Java для реализации и могу, если потребуется, разместить MWE здесь. Однако я опасаюсь, что это может сместить фокус со сценария на программирование, которое здесь не является проблемой (насколько я могу судить).
решение1
OP просит предоставить метод обнаружения одноранговых узлов в сети без каких-либо сведений об этих узлах, согласноэтот источникmDNS требует как минимум знания имени хоста каждого однорангового узла.
В результате mDNS не является приемлемым решением этой проблемы в описанном виде.
Согласнона этот ответ, о многоадресной рассылке, то, о чем вы просили, возможно. Это подразумевает использование опции сокета SO_REUSEADDR. Когда вы используете эту опцию сокета, она позволяет нескольким сокетам прослушивать одну и ту же комбинацию адрес:порт, пока;
- Адрес является многоадресным адресом; и
- SO_RESUSEADDR устанавливается для каждого сокета, который пытается привязаться к комбинации адрес:порт.
Однако, по словамэтот ответ, вам также может потребоваться установить SO_BROADCAST на каждом сокете, что, конечно, не интуитивно понятно! Однако в моих собственных тестах с использованием Python на Windows мне НЕ нужно было этого делать, поэтому не уверен, насколько это законный ответ, я упоминаю его на случай, если вы обнаружите, что застряли, хотя я считаю это потенциально устаревшим, в данный момент я тестирую на Windows 10.
Вот пример кода, который я протестировал, не выдает ошибок, это часть автоматизированного теста, который использует маяки для подключения рабочего процесса к процессу брокера. Этот тест проходит при запуске на одном узле, на нескольких узлах я его еще не тестировал
import socket, struct
MCAST_GRP = ''
MCAST_PORT = 1234
MULTICAST_TTL = 2
def create_beacon_listener():
sock = socket.socket(
socket.AF_INET,
socket.SOCK_DGRAM,
socket.IPPROTO_UDP
)
sock.setsockopt(
socket.SOL_SOCKET,
socket.SO_REUSEADDR,
1
)
sock.setblocking(0)
sock.bind(( MCAST_GRP, MCAST_PORT ))
multicast_grp_req = struct.pack(
"4sl",
socket.inet_aton(MCAST_GRP),
socket.INADDR_ANY
)
sock.setsockopt(
socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
multicast_grp_req
)
return sock
Приведенный выше код возвращает прослушивающий сокет на желаемом групповом адресе MCAST_GRP и порту MCAST_PORT. И да, MCAST_GRP установлен на пустую строку, что означает, что вы фактически прослушиваете все группы адресов многоадресной рассылки. Это, похоже, ограничение либо в Windows, либо в моих знаниях, вероятно, последнее.
В любом случае использование определенного адреса в переменной MCAST_GRP приведет к ошибке, поэтому использование пустой строки, по крайней мере, дает код для решения проблемы, описанной автором.
Этот код можно повторно использовать несколько раз в одном и том же процессе, хотя я еще не проверял, могут ли несколько процессов успешно его использовать. Я тестировал с использованием фреймворка asyncio python, поэтому несколько сокетов прослушивают один и тот же поток.
Кстати, для кроссплатформенной поддержки вы также можете заставить этот код работать на операционных системах nix, и на этих системах вы можете установить MCAST_GRP на определенный адрес.
РЕДАКТИРОВАТЬ:
Недавно я наткнулся наэтот ресурс от MSчто дает пример, который, кажется, позволяет использовать определенный адрес группы multicast, а не привязываться ко всем. Он включает установку некоторых дополнительных опций в переменной multicast_grp_req. Также пример — это код C++, а не python, но они достаточно похожи, чтобы уловить суть.
Надеюсь это поможет :)