【问题标题】:How to send multicast messages and reuse a port in Erlang?如何在 Erlang 中发送多播消息并重用端口?
【发布时间】:2010-06-29 04:31:38
【问题描述】:

我的程序有了一个良好的开端,我的第一个真正的 Erlang 程序。 我让它监听消息,阅读它们并解析它们。我也有它发送给他们。 困扰我的一件小事是我无法在端口 5353 上发送,我已经尝试了所有方法。 我机器上的所有其他应用程序都可以在端口 5353、SubEthaEdit、iTunes、iChat 上监听和发送。

解决方案必须在端口 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 的查询,用于查找本地网络上的其他实例,请注意它显示的是 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 多播有任何神秘的见解?更新,以便我可以尝试接受答案。我想我就是做不到。

【问题讨论】:

    标签: erlang multicast bonjour zeroconf


    【解决方案1】:

    已更新:好的,我找到了我认为可行的解决方案。关键点似乎与加入多播组有关。

    {ok, Socket} = gen_udp:open(Port=5353, [binary, {active, false}, {reuseaddr, true},
                                            {ip, Addr}, {add_membership, {Addr, IAddr}}]).
    
    1. Addr:多播组(例如 {224, 0, 0, 251}
    2. IAddr 是本地 IP 接口(例如可以使用默认的 {0,0,0,0})

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

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        【解决方案3】:

        你试图打开一个已经打开的套接字?你不能使用同一个套接字来发送接收吗?

        【讨论】:

        • 我不这么认为,因为我需要通过 {broadcast,true} 选项进行发送。
        • 当您发送消息时,无法使用 inet:setopts/2 更改 {broadcast, true/false} 吗?
        • 我无法让它发送带有任何设置的消息周期。
        猜你喜欢
        • 2013-02-07
        • 2017-06-26
        • 2021-05-28
        • 2019-07-23
        • 2013-03-14
        • 2016-10-04
        • 1970-01-01
        • 2014-06-07
        • 2023-04-02
        相关资源
        最近更新 更多