我有一个有效的IPv4配置,用于在Wildfly 10.1作为服务器的富Java客户端中使用ActiveMQ。我试图切换到IPv6,它不再起作用了。问题是,上下文查找检索包含IPv6范围id的ServerLocator对象,例如: [FD00 :: d7dc:b4cc:2e2a:EA1%enp0s3]
但此范围仅在服务器上有效。当客户端尝试连接到ServerLocator中的服务器时,它显然不能,因为enp0s3是服务器上的接口而不是客户端上的接口。当我在调试模式下删除作用域时,应用程序再次运行没有问题。所以这只是错误的范围...
有没有办法设置服务器,只发送没有范围的地址?服务器在Java 8上运行,OS在Centos 7上运行。
我的客户代码是:
String JMS_CONNECTION_FACTORY_JNDI = "jms/RemoteConnectionFactory";
Context context = getApplicationManager().getConnectionHandler().getContext();
TopicConnectionFactory cf = (TopicConnectionFactory) context.lookup(JMS_CONNECTION_FACTORY_JNDI);
topicConnection = cf.createTopicConnection();
正确设置了上下文属性,适用于IPv4。
配置很标准:
<interfaces>
<interface name="management">
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
</interface>
<interface name="public">
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" port="${jboss.http.port:8080}"/>
<socket-binding name="https" port="${jboss.https.port:8443}"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">
<remote-destination host="localhost" port="25"/>
</outbound-socket-binding>
</socket-binding-group>
信息:
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
<server name="default">
<security enabled="false"/>
<security-setting name="#">
<role name="guest" send="true" consume="true" create-durable-queue="true" delete-durable-queue="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
</security-setting>
<address-setting name="#" dead-letter-address="jms.queue.DLQ" expiry-address="jms.queue.ExpiryQueue" max-size-bytes="10485760" page-size-bytes="2097152" message-counter-history-day-limit="10"/>
<http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor"/>
<http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput">
<param name="batch-delay" value="50"/>
</http-connector>
<in-vm-connector name="in-vm" server-id="0"/>
<http-acceptor name="http-acceptor" http-listener="default"/>
<http-acceptor name="http-acceptor-throughput" http-listener="default">
<param name="batch-delay" value="50"/>
<param name="direct-deliver" value="false"/>
</http-acceptor>
<in-vm-acceptor name="in-vm" server-id="0"/>
<jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
<jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
<jms-queue name="simulationServerQueue" entries="queue/simulationServerQueue java:/jms/queue/simulationServerQueue"/>
<jms-queue name="simulationWrapperQueue" entries="queue/simulationWrapperQueue java:/jms/queue/simulationWrapperQueue"/>
<jms-topic name="StatusMessaging" entries="topic/StatusMessaging java:/jms/queue/StatusMessaging"/>
<jms-topic name="SimulationMessaging" entries="topic/SimulationMessaging java:/jms/queue/SimulationMessaging"/>
<connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
<connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
<pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" transaction="xa"/>
</server>
和属性:
jboss.bind.address=[fd00::d7dc:b4cc:2e2a:ea1]
java.rmi.server.hostname=[fd00::d7dc:b4cc:2e2a:ea1]
jboss.http.port=8080
相同的上下文(由getConnectionHandler()。getContext();)检索并且配置适用于EJB查找而没有问题。我可以通过JNDI查找接口并在服务器上执行代码。
仅影响主题连接(使用ActiveMQ)。而且只是因为SCOPE。如果我在ActiveMQConnectionFactory.readExternal(..)中的URL中以调试模式删除范围(enp0s3),则ActiveMQ可以正常工作。
我尝试使用Wildfly 11.0.0.Final错误更改为
java.net.UnknownHostException: no such interface enp0s3
at java.net.Inet6Address.initstr(Inet6Address.java:487)
at java.net.Inet6Address.<init>(Inet6Address.java:408)
at java.net.InetAddress.getAllByName(InetAddress.java:1181)
at java.net.InetAddress.getAllByName(InetAddress.java:1126)
at java.net.InetAddress.getByName(InetAddress.java:1076)
at io.netty.util.internal.SocketUtils$8.run(SocketUtils.java:146)
所以问题是一样的。不会为JMS客户端剥离范围标识。
我做了一个小程序来检查java实现以获取InetAddress:
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface netInterface = interfaces.nextElement();
Enumeration<InetAddress> address = netInterface.getInetAddresses();
while (address.hasMoreElements()) {
InetAddress addr = address.nextElement();
if (addr instanceof Inet6Address) {
Inet6Address inet6addr = (Inet6Address) addr;
if (!inet6addr.isLinkLocalAddress() && !inet6addr.isLoopbackAddress())
System.out.println(netInterface.getName() +":"+ inet6addr.isLinkLocalAddress() +":"+ inet6addr +" - "+ inet6addr.getScopedInterface());
}
}
}
在Windows上返回:
eth2:false:/fd00:0:0:0:309c:ae5c:b57c:da62 - null
因此没有设定范围。在第7期:
enp0s3:false:/fd00:0:0:0:d7dc:b4cc:2e2a:ea1%enp0s3 - name:enp0s3 (enp0s3)
所以范围设置在centos上,即使它不是本地链接。我假设在查找过程中使用了类似的东西?有什么想法吗?
由于这似乎是NettyConnector的一个问题,我找到了一个解决方法。这不好,但似乎有效:
String JMS_CONNECTION_FACTORY_JNDI = "jms/RemoteConnectionFactory";
Context context = getApplicationManager().getConnectionHandler().getContext();
TopicConnectionFactory cf = (TopicConnectionFactory) context.lookup(JMS_CONNECTION_FACTORY_JNDI);
// TODO: Remove if fixed in Netty
// THIS IS A PATCH SINCE NETTYCONNECTOR DOES NOT STRIP IPv6 SCOPE
if (cf instanceof ActiveMQJMSConnectionFactory) {
TransportConfiguration[] o = ((ActiveMQJMSConnectionFactory) cf).getStaticConnectors();
for (TransportConfiguration tc : o) {
String host = tc.getParams().get("host").toString();
tc.getParams().put("host", stripScope(host));
}
}
stripScope定义为:
private String stripScope(String ipV6host) {
// only if it contains a %
if (ipV6host != null && ipV6host.contains("%")) {
// Strip [ and ] if any
if (ipV6host.charAt(0) == '[') {
if (ipV6host.length() > 2 && ipV6host.charAt(ipV6host.length() - 1) == ']') {
ipV6host = ipV6host.substring(1, ipV6host.length() - 1);
} else {
// no closing ] return input value
return ipV6host;
}
}
if (Character.digit(ipV6host.charAt(0), 16) != -1 || (ipV6host.charAt(0) == ':')) {
// see if it is IPv6 address
byte[] addr;
if (IPAddressUtil.textToNumericFormatV4(ipV6host) == null
&& (addr = IPAddressUtil.textToNumericFormatV6(ipV6host)) != null) {
try {
return InetAddress.getByAddress(addr).getHostAddress();
} catch (UnknownHostException e) {
}
}
}
}
return ipV6host;
}
这需要进行测试......这只是第一个工作黑客...欢迎任何评论/更好的解决方案。