Как отправлять многоадресные сообщения и повторно использовать порт в Erlang?
Я хорошо начал свою программу, мою первую программу REAL Erlang. Я слушаю сообщения, читаю и разбираю их. У меня также есть его отправка. Одна маленькая вещь, которая беспокоит меня, это то, что я не могу отправить на порт 5353, я все перепробовал. Все остальные приложения на моей машине могут прослушивать и отправлять через порт 5353, SubEthaEdit, iTunes, iChat.
Решение ДОЛЖНО транслироваться через порт 5353, и вот почему.
"Если исходный UDP-порт в полученном многоадресном DNS-запросе не является портом 5353, это указывает на то, что клиент, инициирующий запрос, является простым клиентом, который не полностью реализует все многоадресные DNS. В этом случае многоадресный DNS-ответчик ДОЛЖЕН отправить UDP-ответ напрямую обратно клиенту посредством одноадресной передачи на IP-адрес и порт источника пакета запроса. Этот одноадресный ответ ДОЛЖЕН быть обычным одноадресным ответом, который генерируется обычным одноадресным DNS-сервером, например, он ДОЛЖЕН повторять идентификатор запроса. и вопрос, указанный в пакете запроса. "
Все они сообщают порт: 5353 при отправке многоадресных сообщений. Я действительно хочу, чтобы мое приложение играло хорошо и делало то же самое, отправляя на порт 5353. Вот мой модуль в его нынешнем виде.
-module(zeroconf).
-include("zeroconf.hrl").
-export([open/0,start/0]).
-export([stop/1,receiver/0]).
-export([send/1]).
-define(ADDR, {224,0,0,251}).
-define(PORT, 5353).
send(Domain) ->
{ok,S} = gen_udp:open(0,[{broadcast,true}]), % I really want this Port to be 5353 :-(
% this doesn't complain or throw errors but it also doesn't work :-(
%{ok,S} = gen_udp:open(?PORT,[{reuseaddr,true}, {ip,?ADDR}, {broadcast,true},multicast_ttl,4}, {multicast_loop,false}, binary]),
P = #dns_rec{header=#dns_header{},qdlist=[#dns_query{domain=Domain,type=ptr,class=in}]},
gen_udp:send(S,?ADDR,?PORT,inet_dns:encode(P)),
gen_udp:close(S).
Вот как выглядит какой-то вывод.
Это QUERY от SubEthaEdit, ищущий другие экземпляры в локальной сети, обратите внимание, что там написано Port: 5353
From: {192,168,0,105}
Port: 5353
Data: {ok,{dns_rec,{dns_header,0,true,'query',true,false,false,false,false,0},
[],
[{dns_rr,"_see._tcp.local",ptr,in,0,0,
"jhr@Blackintosh._see._tcp.local",undefined,[],
false}],
[],[]}}
Теперь вот запрос из моего модуля, который ищет экземпляры iTunes в локальной сети, обратите внимание, что там написано: Порт: 59795 С таким кодом, как сейчас, этот порт является случайным. Я действительно хочу, чтобы это было 5353.
From: {192,168,0,105}
Port: 59795
Data: {ok,{dns_rec,{dns_header,0,false,'query',false,false,false,false,false,
0},
[{dns_query,"_daap._tcp.local",ptr,in}],
[],[],[]}}
У кого-нибудь есть какое-то загадочное понимание UDP многоадресной рассылки вообще? Обновление, чтобы я мог попытаться принять ответ. Я думаю, что просто не могу этого сделать.
3 ответа
ОБНОВЛЕНО: хорошо, я нашел то, что я считаю рабочим решением. Кажется, решающий момент связан с присоединением к многоадресной группе.
{ok, Socket} = gen_udp:open(Port=5353, [binary, {active, false}, {reuseaddr, true},
{ip, Addr}, {add_membership, {Addr, IAddr}}]).
- Адрес: многоадресная группа (например, {224, 0, 0, 251}
- IAddr является локальным IP-интерфейсом (например, может использовать значение по умолчанию {0,0,0,0})
(Конечно, убедитесь, что у вас не запущен демон DNS, который может вступить в конфликт)
Извините, у меня недостаточно репутации для ответа на {трансляцию, правда} в сообщении Эмиля.
Флаг сокета SO_BROADCAST (который, как я предполагаю, соответствует) должен быть установлен, иначе sendto(широковещательный адрес) не удастся. Это предохранитель для предотвращения злоупотреблений или ошибок в программах, которые не предназначены для трансляции. В противном случае защищенным программам придется самим проверять широковещательные адреса.
включение SO_BROADCAST не останавливает вас от отправки не вещательных пакетов. (опять же, если предположить, что материал erlang просто сопоставляется напрямую с setsockopts; я не знаю erlang, просто работаю в сети!)
Возможно, вы захотите попробовать strace, чтобы увидеть, какие системные вызовы действительно происходят. ищите socket(), а затем, что происходит с этим дескриптором файла.
Вы пытаетесь открыть сокет, который уже открыт? Разве вы не можете использовать один и тот же сокет для отправки и получения?