我在尝试让 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 的替代品,但看起来其他声称可以替代它的库实际上还不能进行多播,这让它们有点毫无意义。:()
这里发生了什么?