我们有许多托管多个 IP 地址的服务器。其他的是所谓的虚拟 IP(“VIP”)。
我们希望使 Java 应用程序能够建立一个传出连接,该连接将指定的虚拟 IP 而不是主机 IP 地址列为源地址。
这是我们尝试过的。中列出的 ip 地址InetAddress#getByAddress
是虚拟 ip 地址。该属性url
是用户指定的要连接的目标 url。
public void attemptConnection() {
try {
Proxy proxy = new Proxy(Proxy.Type.HTTP,
new InetSocketAddress(InetAddress.getByAddress(new byte[]{(byte)10,(byte)252,(byte)47,(byte)33}), 0));
final URL _url = new URL(url);
final URLConnection conn = _url.openConnection(proxy);
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
in.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
上面的代码是根据这个答案建模的
我们正在用 Python 测试这个SimpleHTTPServer
,简单地运行python -m SimpleHTTPServer
然后尝试连接。
如果我们在 Java 代码中不使用代理,那么连接就可以正常工作。
但是,一旦定义了 VIP 代理,我们就会拒绝连接:
java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:327)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:193)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:180)
at java.net.Socket.connect(Socket.java:546)
at java.net.Socket.connect(Socket.java:495)
at sun.net.NetworkClient.doConnect(NetworkClient.java:178)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:409)
at sun.net.www.http.HttpClient$2.run(HttpClient.java:457)
at java.security.AccessController.doPrivileged(Native Method)
at sun.net.www.http.HttpClient.privilegedOpenServer(HttpClient.java:454)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:521)
at sun.net.www.http.HttpClient.<init>(HttpClient.java:240)
at sun.net.www.http.HttpClient.New(HttpClient.java:321)
at sun.net.www.http.HttpClient.New(HttpClient.java:338)
at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:935)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:914)
at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:801)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1139)
at com.ocado.dsi.ConnectToUrl.attemptConnection(ConnectToUrl.java:38)
at com.ocado.dsi.ConnectToUrl.run(ConnectToUrl.java:56)
at com.ocado.dsi.ConnectToUrl.main(ConnectToUrl.java:64)
任何想法为什么?
更新
直接在套接字上指定本地地址时,该过程可以正常工作。
我设置了一个 Python 简单的套接字服务器,在端口 8000 上进行监听,就像SimpleHTTPServer
上面使用的一样。使用具有所需本地地址的套接字从 Java 连接到该地址按预期工作:python 服务器将传入的连接源地址识别为用户定义的地址。
Socket s = new Socket(InetAddress.getByAddress(new byte[]{(byte)10,(byte)252,(byte)47,(byte)33}), 8000, InetAddress.getByAddress(new byte[]{(byte)10,(byte)97,(byte)5,(byte)147}), 0);
s.close();
我将深入Socket#setSocketImplFactory
研究是否可以通过自定义每个创建的套接字来解决问题。
问题是两者都Socket#setSocketImplFactory
使URL.setURLStreamHandlerFactory
您能够覆盖默认实现,但不允许您访问默认实现,因此它们似乎是全有或全无的覆盖。当您只想在顶部添加逻辑时,这非常烦人。