如何在 java.net.URLConnection 上指定本地地址?
Posted
技术标签:
【中文标题】如何在 java.net.URLConnection 上指定本地地址?【英文标题】:How can I specify the local address on a java.net.URLConnection? 【发布时间】:2010-09-10 15:19:26 【问题描述】:我的 Tomcat 实例正在监听多个 IP 地址,但我想控制在打开 URLConnection
时使用哪个源 IP 地址。
如何指定?
【问题讨论】:
如果我的 tomcat 正在侦听具有不同网关(在不同子网上)的两个 IP 地址,如果我指定为代理的 IP 地址的网关暂时不可用会发生什么,openConnection 会抛出异常或将它回退到另一个网关/IP? 【参考方案1】:这应该可以解决问题:
URL url = new URL(yourUrlHere);
Proxy proxy = new Proxy(Proxy.Type.DIRECT,
new InetSocketAddress(
InetAddress.getByAddress(
new byte[]your, ip, interface, here), yourTcpPortHere));
URLConnection conn = url.openConnection(proxy);
你就完成了。 不要忘记很好地处理异常,并根据您的情况更改值。
啊,我省略了导入语句
【讨论】:
这失败了 "java.lang.IllegalArgumentException: type DIRECT is not compatible with address my.ip.address.here"。深入研究 Proxy 的源代码,我发现每当尝试输入 DIRECT 时都会抛出此异常。 这对我不起作用,我不明白为什么。没有代理就好了。指定代理和虚拟 IP(本地主机上的第二个 IP 地址)后,我得到一个ConnectException
。使用指定了本地地址的 4-arg 套接字构造函数,使用套接字而不是 URLConnection
进行测试也可以正常工作。其他人能否确认他们是否在本地接口上使用了第二个 IP 的上述解决方案?
我应该使用哪个本地端口?不是应该由较低级别的 TCP 堆栈设置以避免冲突并使端口可重用吗?
此代码无法运行。自 JDK 1.5 以来,我已经查看了 java.net.Proxy
,并且总是会在构造函数中抛出异常。见第一条评论。这个答案不正确【参考方案2】:
使用 Apache commons HttpClient 我还发现以下工作(为了清楚起见删除了 try/catch):
HostConfiguration hostConfiguration = new HostConfiguration();
byte b[] = new byte[4];
b[0] = new Integer(192).byteValue();
b[1] = new Integer(168).byteValue();
b[2] = new Integer(1).byteValue();
b[3] = new Integer(11).byteValue();
hostConfiguration.setLocalAddress(InetAddress.getByAddress(b));
HttpClient client = new HttpClient();
client.setHostConfiguration(hostConfiguration);
GetMethod method = new GetMethod("http://remoteserver/");
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler(3, false));
int statusCode = client.executeMethod(method);
if (statusCode != HttpStatus.SC_OK)
System.err.println("Method failed: " + method.getStatusLine());
byte[] responseBody = method.getResponseBody();
System.out.println(new String(responseBody));");
但是,我仍然想知道如果 IP 的网关发生故障(本例中为 192.168.1.11)会发生什么情况。下一个网关会被尝试还是会失败?
【讨论】:
使用 4.1 代码库(也许更早?),您可以在一行中指定本地 IP 地址:object.getParams().setParameter("http.route.local-address ", ipAddress ),其中 object 是 HttpClient 或 HttpRequest。【参考方案3】:显而易见的可移植方式是在 URL.openConnection 中设置代理。代理可以在本地主机中,然后您可以编写一个非常简单的代理来绑定客户端套接字的本地地址。
如果不能修改URL连接的源,可以在调用URL构造函数时替换URLStreamHandler,也可以通过URL.setURLStreamHandlerFactory全局替换。然后 URLStreamHandler 可以委托给默认的 http/https 处理程序,修改 openConnection 调用。
更极端的方法是完全替换处理程序(也许扩展 JRE 中的实现)。或者,可以使用替代(开源)http 客户端。
【讨论】:
【参考方案4】:手动设置套接字工作正常...
private HttpsURLConnection openConnection(URL src, URL dest, SSLContext sslContext)
throws IOException, ProtocolException
HttpsURLConnection connection = (HttpsURLConnection) dest.openConnection();
HttpsHostNameVerifier httpsHostNameVerifier = new HttpsHostNameVerifier();
connection.setHostnameVerifier(httpsHostNameVerifier);
connection.setConnectTimeout(CONNECT_TIMEOUT);
connection.setReadTimeout(READ_TIMEOUT);
connection.setRequestMethod(POST_METHOD);
connection.setRequestProperty(CONTENT_TYPE, SoapConstants.CONTENT_TYPE_HEADER);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setSSLSocketFactory(sslContext.getSocketFactory());
if ( src!=null )
InetAddress inetAddress = InetAddress.getByName(src.getHost());
int destPort = dest.getPort();
if ( destPort <=0 )
destPort=SERVER_HTTPS_PORT;
int srcPort = src.getPort();
if ( srcPort <=0 )
srcPort=CLIENT_HTTPS_PORT;
connectionSocket = connection.getSSLSocketFactory().createSocket(dest.getHost(), destPort, inetAddress, srcPort);
connection.connect();
return connection;
【讨论】:
只是为了确保我正确理解这一点(因为我已经对其进行了测试并且它有效),只有您创建套接字的部分我想对此进行一些澄清。 createSocket() 方法强制底层套接字工厂使用您刚刚创建的套接字?因为我没有看到在其他任何地方使用 connectionSocket 变量。文档只提到“在给定端口返回连接到指定主机的现有套接字上的套接字。”以上是关于如何在 java.net.URLConnection 上指定本地地址?的主要内容,如果未能解决你的问题,请参考以下文章
如何在异步任务中调用意图?或者如何在 onPostExecute 中开始新的活动?