JmDNS似乎在Mac OS X上根本不起作用

时间:2013-10-23 06:04:54

标签: java jmdns mdns

我一直在尝试让JmDNS在Mac OS X上运行时遇到问题。症状是我可以在网络上发现任何服务,除了我自己计算机上的服务。它们是在本地主机上还是在我的计算机上运行的虚拟机上无关紧要 - 在任何一种情况下,它们都不会从list调用回来。

我设法将我们正在做的事情压缩到一个通过Windows但在Mac OS X上失败的测试。现在的问题是我无法弄清楚问题出在哪里。

@Test
public void testAdvertisingOverLoopback() throws Exception
{
    // happens on any address but loopback is the strangest
    InetAddress address = InetAddress.getLoopbackAddress();
    String type = "_test._tcp.local.";
    String name = "test-service";
    int port = 9999;
    Map<String, String> properties = ImmutableMap.of("key", "value");

    // simulate the service starting up. issue also occurs in separate VMs
    try (JmDNS serviceDns = JmDNS.create(address))
    {
        serviceDns.registerService(ServiceInfo.create(type, name, port,
                                   0, 0, properties));

        try (JmDNS clientDns = JmDNS.create(address))
        {
            ServiceInfo[] services = clientDns.list(type);

            // One of the entries should:
            assertThat(services, is(arrayContaining(allOf(

                // Contain an address which matches the one we advertised (culling those which might
                // be registered by other tests which happen to run at the same time.)
                hasProperty("inetAddresses", arrayContaining(sameAddressAs(address))),

                // Match the parameters we specified in the call to list.
                hasProperty("application", equalTo("test")),
                hasProperty("protocol", equalTo("tcp")),
                hasProperty("domain", equalTo("local")),

                // Match the info we advertised.
                hasProperty("port", equalTo(9999)),
                hasCustomProperty("key", "value")
            ))));
        }
    }
}

private static Matcher<InetAddress> sameAddressAs(final InetAddress address)
{
    return new TypeSafeMatcher<InetAddress>()
    {
        @Override
        protected boolean matchesSafely(InetAddress inetAddress)
        {
            return Arrays.equals(address.getAddress(), inetAddress.getAddress());
        }

        @Override
        public void describeTo(Description description)
        {
            description.appendText("same address as ");
            description.appendValue(address.getHostAddress());
        }
    };
}

private static Matcher<ServiceInfo> hasCustomProperty(final String key,
                                                      final String value)
{
    return new TypeSafeMatcher<ServiceInfo>()
    {
        @Override
        protected boolean matchesSafely(ServiceInfo serviceInfo)
        {
            return value.equals(serviceInfo.getPropertyString(key));
        }

        @Override
        public void describeTo(Description description)
        {
            description.appendText("has custom mDNS property ");
            description.appendValue(key);
            description.appendText(" = ");
            description.appendValue(value);
        }
    };
}

在调试器中,我可以看到它没有将套接字绑定到任何特定地址,只是一个特定的端口。但它会将其设置为特定的界面。

我在Wireshark中看到的是,数据包是从我机器的公共IP(en0的地址)发出的,即使lo0是我用于测试的接口。我也看到了查询和响应数据包。回复 回来。

但是在Java方面,我看到它调用DatagramSocket#receive(DatagramPacket)并且从未收到数据包。

(我也花了半天时间寻找JmDNS的替代品,但看起来其他声称要替代它的库实际上不能进行多播,这使得它们有点无意义。:()< / p>

这里发生了什么?

1 个答案:

答案 0 :(得分:1)

正在发生的事情是OS X中内置的zeroconf服务正在获取数据包。

JmDNS假设它是侦听该端口的机器上运行的唯一守护程序。因为它使用的代码故意绑定到0.0.0.0,所以对正在使用的端口没有异常(显然这是Socket API的&#34;特性&#34;)

对于Windows,这样可以正常工作,因为从未运行过另一个zeroconf守护程序。

对于Mac OS X,它保证会失败,因为内置的一直在运行。

我想在Linux上,你会得到不同的结果,这取决于你正在运行的发行版以及你安装了哪些服务。

我正在处理的问题的解决方案是在CFNetServices之上制作完全不同的API。