如何在Erlang中发送多播消息并重用端口?

时间:2009-11-17 02:38:32

标签: erlang multicast bonjour zeroconf

我的程序是我的第一个真正的Erlang程序。 我让它听取消息,阅读它们并解析它们。我也发送它们。 困扰我的一件小事是我不能在5353号港口发送,我已经尝试了一切。 我的机器上的所有其他应用程序都可以通过端口5353,SubEthaEdit,iTunes,iChat进行监听和发送。

解决方案必须在端口5353上广播发送,这就是原因。

“如果收到的多播DNS查询中的源UDP端口不是端口   5353,这表示发起查询的客户端是a   简单的客户端,没有完全实现所有的多播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的QUERY在本地网络上查找其他实例,请注意它显示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}],
                   [],[]}}

现在,我的模块中有一个QUERY来查找本地网络上的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 个答案:

答案 0 :(得分: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})
  3. (当然,请确保您没有运行可能冲突的DNS守护进程)

答案 1 :(得分:1)

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

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

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

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

答案 2 :(得分:0)

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