我一直在尝试让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>
这里发生了什么?
答案 0 :(得分:1)
正在发生的事情是OS X中内置的zeroconf服务正在获取数据包。
JmDNS假设它是侦听该端口的机器上运行的唯一守护程序。因为它使用的代码故意绑定到0.0.0.0,所以对正在使用的端口没有异常(显然这是Socket API的&#34;特性&#34;)
对于Windows,这样可以正常工作,因为从未运行过另一个zeroconf守护程序。
对于Mac OS X,它保证会失败,因为内置的一直在运行。
我想在Linux上,你会得到不同的结果,这取决于你正在运行的发行版以及你安装了哪些服务。
我正在处理的问题的解决方案是在CFNetServices之上制作完全不同的API。