2013-10-23 44 views
1

我一直有问题试图让JmDNS在Mac OS X上工作。症状是我可以发现网络上的任何服务,除了我的自己的电脑。无论他们是在本地主机还是在我的计算机上运行的虚拟机上 - 无论是哪种情况,他们都不会从list调用回来。JmDNS在Mac OS X上似乎没有任何作用

我设法将我们正在做的事情压缩到在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的替代品,但它看起来像声称替换它的其他库不能真正实现多播,这使得它们有点没有意义:()

这到底是怎么回事呢?

回答

1

这是怎么回事是内置于OS X零配置服务是获取数据包。

JmDNS假定它是在计算机上运行的唯一守护进程在端口上监听,因为它使用的代码故意绑定到0.0.0.0,所以并没有抛出关于端口的异常(显然这是Socket API的一个“特性”。)

对于Windows,这很好,因为永远不会有另一个zeroconf守护进程在运行。

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

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

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

+0

“对于Windows,这可以正常工作,因为永远不会有另一个zeroconf守护进程在运行。”显然现在不再与Windows 10:https://www.slightfuture.com/technote/windows-mdns-dnssd – Grodriguez

+0

阅读您的答案,我试图禁用mDNS守护进程根据:http://www.dgkapps.com/博客/ osx-tips/osx-tips-turn-off-disable-bonjour-from-the-command-line /并玩弄配置。虽然deamons似乎已经关闭('ps aux | grep mDNS'),但它们似乎仍然会干扰jmDNS库 - 任何想法? – Wingo

+0

我完全采取了另一种方式 - 禁用jMDNS for macOS,并使用系统API来注册我的记录。 – Trejkaz