JmDNS вообще не работает в Mac OS X

У меня возникли проблемы при попытке заставить 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, но похоже, что другие библиотеки, которые утверждают, что заменяют его, еще не могут на самом деле выполнять многоадресную рассылку, что делает их немного бессмысленными. :( )

Что здесь происходит?


person Trejkaz    schedule 23.10.2013    source источник


Ответы (1)


Происходит то, что встроенная служба zeroconf в OS X получает пакеты.

JmDNS предполагает, что это единственный демон, работающий на машине и прослушивающий этот порт. Поскольку код, который он использует, преднамеренно привязывается к 0.0.0.0, никаких исключений относительно используемого порта не возникает (очевидно, это «функция» Socket API).

Для Windows это работает нормально, потому что другой демон zeroconf никогда не работает.

Для Mac OS X он гарантированно не работает, потому что встроенный работает всегда.

Я предполагаю, что в Linux вы получите смешанные результаты, в зависимости от того, какой дистрибутив вы используете и какие службы вы установили.

Решение проблемы, над которой я работаю, состоит в том, чтобы создать совершенно другой API поверх CFNetServices.

person Trejkaz    schedule 12.03.2014
comment
Для Windows это работает нормально, потому что другой демон zeroconf никогда не работает. По-видимому, больше не с Windows 10: slightfuture.com/technote/windows-mdns-dnssd - person Grodriguez; 06.04.2016
comment
Читая ваш ответ, я пытался отключить демоны mDNS в соответствии с: dgkapps.com/blog/osx-tips/, а также экспериментировать с конфигурациями. Хотя демоны, похоже, отключены (ps aux | grep mDNS), они все еще мешают работе библиотеки jmDNS — есть какие-нибудь мысли? - person Wingo; 31.10.2017
comment
Я пошел совсем другим путем — отключил jmDNS для macOS и использовал системные API для регистрации своих записей. - person Trejkaz; 01.11.2017