Why is inet:/0.0.0.0 interpreted as inet:/0:0:0:0:0:0:0:0 by com.sun.net.httpserver.HttpServer?
We found this issue while implementing a reconnect logic for a WS endpoint using JAX-WS stack deployed on Glassfishv2.1 server. We deploy the web service on a cluster environment. To simplify the deployment, we use 0.0.0.0 as the IP on which the endpoint needs to be published, so that it can be accessed from all available IPs pertaining to the nodes of the cluster. Following is the code snippet for initialization of the WS(Web Service):
import javax.xml.ws.Endpoint;
.
.
//Implementor is the corresponding implementation object for the WS
Endpoint receiver = Endpoint.create(new Implementor());
.
receiver.setExecutor(threadPoolExecutor);
receiver.publish ("http://0.0.0.0:9545/context");
We call receiver.stop() to stop publishing the endpoint in our cleanup code. That's where we receive a null pointer exception with the following stack trace:
java.lang.NullPointerException
at com.sun.xml.ws.transport.http.server.ServerMgr.removeContext(ServerMgr.java:123)
at com.sun.xml.ws.transport.http.server.HttpEndpoint.stop(HttpEndpoint.java:110)
at com.sun.xml.ws.transport.http.server.EndpointImpl.stop(EndpointImpl.java:167
While trying to find the cause of the NPE, we found that the ServerMgr class depends on the InetSocketAddress of the HttpServer that listen on the ip:port of the URL where the WS endpoint is published, to retrieve some state information from a map. Since the inet address "inet:/0.0.0.0" is interpreted as "inet:/0:0:0:0:0:0:0:0" it could not find the entry in the map and hence the NPE. Here is the source code of ServerMgr.
In order to prove that this is in fact the problem, we tried to replicate the logic of the ServerMgr code related to InetSocketAddress as the following program:
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.Http开发者_如何转开发Server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main {
static final String URL_1 = "http://0.0.0.0:9545/context";
static final String URL_2 = "http://127.0.0.1:9548/context";
static final String URL_3 = "http://10.226.90.217:9549/context";
public void testUrl(String address){
try {
URL url = new URL(address);
Map<InetSocketAddress, Integer> map = new HashMap<InetSocketAddress, Integer>();
InetSocketAddress iaddr = new InetSocketAddress(url.getHost(), url.getPort());
map.put(iaddr, 1);
HttpServer server = HttpServer.create(iaddr, 5);
HttpContext context = server.createContext(url.toURI().getPath());
server.start();
System.out.println("original inet:"+iaddr+" and final inet:"+context.getServer().getAddress());
if(iaddr.equals(context.getServer().getAddress())){
System.out.println("equal");
Integer t = map.get(context.getServer().getAddress());
if( t == null){
System.out.println("You won");
}else{
System.out.println("You lose "+t);
}
}else{
System.out.println("not-equal");
}
server.stop(0);
map.clear();
} catch (URISyntaxException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args)
{
Main d = new Main();
d.testUrl(Main.URL_1);
d.testUrl(Main.URL_2);
d.testUrl(Main.URL_3);
}
}
Odd enough we obtain the following result in my WindowsXP box ( Java version 1.6.0_22)
equal--
original inet:/0.0.0.0:9545 and final inet:/0.0.0.0:9545
equal
You lose 1
equal--
original inet:/127.0.0.1:9548 and final inet:/127.0.0.1:9548
equal
You lose 1
equal--
original inet:/10.226.92.47:9549 and final inet:/10.226.92.47:9549
equal
You lose 1
and the following output on my dev box (Linux tahoe 2.6.9-67.EL #1 Wed Nov 7 13:43:31 EST 2007 x86_64 x86_64 x86_64 GNU/Linux) (Java version 1.6.0_17)
run:
original inet:/0.0.0.0:9545 and final inet:/0:0:0:0:0:0:0:0:9545
not-equal
original inet:/127.0.0.1:9548 and final inet:/127.0.0.1:9548
equal
You lose 1
original inet:/10.226.90.217:9549 and final inet:/10.226.90.217:9549
equal
You lose 1
Based on the background - I have two questions:
- a. Why is the 0.0.0.0 is interpreted as IPv6 address ? (In addition, is it a problem with the OS or the JRE ? Is it a bug or a feature ? etc)
- b. Do we have a way to configure JRE to interpret 0.0.0.0 as IPv4 address ? (We want to keep using 0.0.0.0 as the endpoint address as it simplifies deployment of our Web Service)
You can replace the 0.0.0.0
with InetAddress.getLocalHost().getHostAddress();
It will automatically resolve correctly and there is no need of -Djava.net.preferIPv4Stack=true
Have you tried by forcing the IPv4 choice as a variable to the java executable?
-Djava.net.preferIPv4Stack=true
Take a look here and here..
It's also possible to force IPv4 from your code with System.setProperty("java.net.preferIPv4Stack" , "true");
精彩评论