2008-09-18 9 views
11

Meine Tomcat-Instanz hört mehrere IP-Adressen ab, aber ich möchte steuern, welche Quell-IP-Adresse beim Öffnen einer URLConnection verwendet wird.Wie kann ich die lokale Adresse auf einer java.net.URLConnection angeben?

Wie kann ich das angeben?

+1

Wenn mein Kater auf zwei IP-Adressen lauscht mit verschiedenen Gateways (in verschiedenen Subnetzen) was, wenn das Gateway für die IP-Adresse passieren werde ich als Proxy angeben ist vorübergehend nicht verfügbar, wird openConnection eine Ausnahme auslösen oder fällt sie auf das andere Gateway/ip zurück? – stian

Antwort

6

Dies sollte den Trick:

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); 

Und du bist fertig. Vergessen Sie nicht, Ausnahmen gut zu behandeln, und ändern Sie natürlich die Werte entsprechend Ihrem Szenario.

Ah und ich die Import-Anweisungen

weggelassen
+7

Dies schlägt mit * "java.lang.IllegalArgumentException: Typ DIRECT ist nicht kompatibel mit Adresse my.ip.address.here" *. Wenn ich in die Quelle für Proxy eintauche, sehe ich, dass diese Ausnahme ausgelöst wird, wenn * der Typ DIRECT versucht wird. – user359996

+0

Das funktioniert nicht für mich und ich kann nicht verstehen warum. Ohne den Proxy ist es in Ordnung. Mit dem Proxy und einer virtuellen IP (zweite IP-Adresse auf meinem localhost) angegeben bekomme ich eine 'ConnectException'. Das Testen mit einem Socket anstelle von "URLConnection" funktioniert auch gut, wenn der 4-Arg-Socket-Konstruktor verwendet wird, in dem die lokale Adresse angegeben ist. Könnte jemand anderes bitte bestätigen, ob die obige Lösung mit einer zweiten IP auf der lokalen Schnittstelle funktioniert? – KomodoDave

+0

Welchen lokalen Port sollte ich verwenden? Soll es nicht von einer niedrigeren Ebene des TCP-Stacks gesetzt werden, um Kollisionen zu vermeiden und Ports wiederverwendbar zu machen? – vbence

1

Der offensichtliche portable Weg wäre, einen Proxy in URL.openConnection zu setzen. Der Proxy kann sich im lokalen Host befinden, Sie können dann einen sehr einfachen Proxy schreiben, der die lokale Adresse des Client-Sockets bindet.

Wenn Sie die Quelle, mit der die URL verbunden ist, nicht ändern können, können Sie URLStreamHandler entweder beim Aufrufen des URL-Konstruktors oder global durch URL.setURLStreamHandlerFactory ersetzen. Der URLStreamHandler kann dann an den standardmäßigen http/https-Handler delegieren und den Aufruf von openConnection ändern.

Eine extremere Methode wäre, den Handler vollständig zu ersetzen (vielleicht die Implementierung in Ihrer JRE zu erweitern). Alternativ stehen alternative (Open Source) HTTP-Clients zur Verfügung.

3

die Apache commons Mit Httpclient Ich habe auch die folgenden gefunden (entfernt try/catch für Klarheit) zu arbeiten:

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));"); 

Allerdings frage ich mich immer noch, was würde passieren, wenn das Gateway der IP ist unten (192.168.1.11 in diesem Fall). Wird das nächste Gateway versucht oder wird es fehlschlagen?

+1

Mit der Codebase 4.1 (und vielleicht früher?) Können Sie die lokale IP-Adresse in einer einzigen Zeile angeben: ** object.getParams(). SetParameter ("http.route.local-Adresse", ipAddress) **, wobei ** object ** entweder der ** HttpClient ** oder der ** HttpRequest ** ist. – user359996

3

fein manuell Buchse Arbeit einstellen ...

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; 
}  
+0

Nur um sicherzugehen, dass ich das richtig verstehe (weil ich es getestet habe und es funktioniert hat), gibt es nur den Teil, wo du einen Socket erstellst, an dem ich ein paar Erklärungen haben möchte.Die Methode createSocket() erzwingt, dass die zugrunde liegende Socket-Factory den soeben erstellten Socket verwendet. Weil ich nicht sehe, dass die Variable connectionSocket irgendwo anders benutzt wird. Die Dokumentation erwähnt nur "Gibt einen Socket über einen vorhandenen Socket, der mit dem angegebenen Host verbunden ist, an dem angegebenen Port zurück." – schwarz