Как отправлять многоадресные сообщения и повторно использовать порт в Erlang?

Я хорошо начал свою программу, свою первую НАСТОЯЩУЮ программу на 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).

Вот как выглядят некоторые результаты.

Это ЗАПРОС от SubEthaEdit, который ищет другие экземпляры в локальной сети, обратите внимание, что он говорит: Порт: 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? Обновление, чтобы я мог попытаться принять ответ. Думаю, я просто не могу этого сделать.


person Community    schedule 17.11.2009    source источник


Ответы (3)


ОБНОВЛЕНО: хорошо, я нашел то, что считаю рабочим решением. Похоже, что решающий момент связан с присоединением к группе многоадресной рассылки.

{ok, Socket} = gen_udp:open(Port=5353, [binary, {active, false}, {reuseaddr, true},
                                        {ip, Addr}, {add_membership, {Addr, IAddr}}]).
  1. Адрес: группа многоадресной рассылки (например, {224, 0, 0, 251}
  2. IAddr - это локальный IP-интерфейс (например, можно использовать {0,0,0,0} по умолчанию)

(Конечно, убедитесь, что вы не запускаете DNS-демон, который может вступить в конфликт)

person jldupont    schedule 17.11.2009

у меня недостаточно ответов, чтобы ответить на обсуждение {broadcast, true} под сообщением Эмиля, извините.

Флаг сокета SO_BROADCAST (который, как я предполагаю, сопоставляется) должен быть установлен, иначе sendto (широковещательный адрес) завершится ошибкой. Это предохранитель для предотвращения злоупотреблений или ошибок в программах, которые не предназначались для трансляции. В противном случае защищенным программам пришлось бы пытаться самостоятельно проверять широковещательные адреса.

включение SO_BROADCAST не мешает вам отправлять нешироковещательные пакеты. (опять же, предполагая, что материал erlang просто отображается напрямую в setsockopts; я не знаю erlang, просто сеть!)

Вы можете попробовать strace, чтобы увидеть, какие системные вызовы на самом деле происходят. ищите socket (), а затем что происходит с этим файловым дескриптором.

person Peter Cordes    schedule 05.12.2009

Вы пытаетесь открыть сокет, который уже открыт? Разве вы не можете использовать один и тот же сокет для отправки и приема?

person emil    schedule 17.11.2009
comment
Я так не думаю, потому что мне нужно передать параметр {broadcast, true} для отправки. - person ; 17.11.2009
comment
Тогда невозможно изменить {broadcast, true / false} с помощью inet: setopts / 2, когда вы отправляете сообщение? - person emil; 02.12.2009
comment
Я не могу заставить его отправлять период сообщения с любым из этого набора или нет. - person ; 05.12.2009