2009-11-17 46 views
7

我已经在我的程序,我的第一个真正的Erlang程序上获得了良好的开端。 我让它听取消息,阅读并解析它们。我也有它发送。 困扰我的一件小事是我无法在端口5353上发送,我尝试了一切。 我的机器上的所有其他应用程序都可以侦听并发送端口5353,SubEthaEdit,iTunes,iChat。如何在Erlang中发送多播消息并重用端口?

该解决方案必须广播发送端口5353,这就是为什么。

“如果在接收多播DNS查询的源UDP端口不是端口 5353,这表示一个客户端的查询是 简单的客户端,它没有完全实现所有组播DNS的。 在这情况下,组播DNS响应者务必通过单播将UDP响应 直接发送回客户端,通过单播发送到查询分组的 源IP地址和端口。该单播响应必须是传统的单播响应,如由常规的 单播DNS服务器;例如,它必须重复查询ID和在查询分组中给出的问题。 “

它们在发送多播消息时都报告端口: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, 
          "[email protected]_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}}]). 
  1. 地址:多播组(例如{224,0,0,251}
  2. IAddr是本地IP接口(例如可以使用默认{0,0,0,0})

(当然,请确保您没有运行可能在冲突中输入DNS守护进程)

0

您尝试打开一个已打开的套接字?你不能使用相同的套接字发送接收吗?

+0

我不这么认为,因为我需要通过{broadcast,true}选项进行发送。 – 2009-11-17 13:21:33

+0

当你发送消息时,用inet:setopts/2不可能改变{broadcast,true/false}吗? – emil 2009-12-01 21:29:01

+0

我无法让它发送消息期限与任何设置或不。 – 2009-12-05 05:07:47

1

没有足够的代表回复在emil的帖子下进行的{broadcast,true}讨论,抱歉。

SO_BROADCAST套接字标志(我假设映射到)必须设置或sendto(广播地址)将失败。这是一项安全措施,可防止不想广播的节目发生滥用或错误。否则,安全的程序将不得不尝试自己检查广播地址。

启用SO_BROADCAST不会阻止您发送非广播数据包。 (同样,假设erlang的东西只是直接映射到setsockopts;我不知道erlang,只是联网!)

您可能想尝试strace来查看实际发生的系统调用。查找socket(),然后发生该文件描述符。