2008-09-18 5 views
9

Ich möchte den Inhalt einer URL lesen, möchte aber nicht "hängen", wenn die URL nicht mehr reagiert. Ich habe einen BufferedReader mit der URL ...Wie kann ich ein Timeout für einen BufferedReader basierend auf einer URLConnection in Java setzen?

URL theURL = new URL(url); 
URLConnection urlConn = theURL.openConnection(); 
urlConn.setDoOutput(true); 
BufferedReader urlReader = new BufferedReader(newInputStreamReader(urlConn.getInputStream())); 
erstellt

... und dann die Schleife begonnen, den Inhalt zu lesen ...

do 
    { 
    buf = urlReader.readLine(); 
    if (buf != null) 
     { 
     resultBuffer.append(buf); 
     resultBuffer.append("\n"); 
     } 
    } 
while (buf != null); 

... aber wenn Das Lesen hängt, dann hängt die Anwendung.

Gibt es einen Weg, ohne den Code auf die Socket-Ebene zu schleifen, um den Lesevorgang "auszuwechseln", wenn nötig?

Antwort

12

Ich denke URLConnection.setReadTimeout ist, was Sie suchen.

+2

Awesome, danke verwenden. Hinzugefügt in 1.5! – dacracot

2

Seit Java 1.5 kann das Lese-Timeout in Millisekunden am zugrunde liegenden Socket über die Methode 'setReadTimeout (int timeout)' der URLConnection-Klasse gesetzt werden.

Beachten Sie, dass es auch die 'setConnectTimeout (int timeout)' gibt, die dasselbe für die anfängliche Verbindung mit dem Remote-Server tun wird, also ist es wichtig, das auch zu setzen.

+1

Öffnet openConnection() nicht die Verbindung, so hat die Einstellung des Zeitlimits für die offene Verbindung eine Auswirkung oder liest sie den Wert auch nach dem Start des Verbindungsprozesses? – William

3

Wenn Sie Java 1.4:

Ich gehe davon aus, die Verbindung Timeout (URLConnection.setConnectTimeout(int timeout)) ist zwecklos, weil Sie eine Art von Streaming tun.

--- nicht töten den Faden --- Es kann unbekannte Probleme verursachen, offene Deskriptoren etc.

Spawn eine java.util.TimerTask, wo Sie überprüft, ob Sie den Prozess abgeschlossen haben, andernfalls schließen die BufferedReader und der Output der URLConnection

ein boolesches Flag isFinished einsetzen und auf true am Ende der Schleife gesetzt und auf false vor der Schleife

TimerTask ft = new TimerTask(){ 
    public void run(){ 
    if (!isFinished){ 
     urlConn.getInputStream().close(); 
     urlConn.getOutputStream().close(); 
    } 
    } 
}; 

(new Timer()).schedule(ft, timeout); 

Dies wird wahrscheinlich eine Ausnahme verursachen, also müssen Sie sie abfangen. Die Ausnahme ist keine schlechte Sache an sich. Ich unterlasse einige Deklarationen (z. B. Finale), so dass die anonyme Klasse auf Ihre Variablen zugreifen kann. Wenn nicht, dann erstellen Sie einen POJO, der eine Referenz verwaltet und diese an die Timertask weiterleitet.

+0

Das ist eine nette Lösung, aber ich denke deine Aufgabe wird nur einmal ausgelöst. Das würde wahrscheinlich für einen langfristigen Übertragungsprozess fehlschlagen, daher wäre es besser, in einem Intervall zu laufen und den Timer zu stoppen, wenn das erledigt ist. Interessante Idee. – jsight

1

Ich habe gerade in einer JVM 1.4-Umgebung an diesem Problem gearbeitet. Die Bestandsantwort besteht darin, die Systemeigenschaften sun.net.client.defaultReadTimeout (Lese-Timeout) und/oder sun.net.client.defaultConnectTimeout zu verwenden. Diese sind unter Networking Properties dokumentiert und können über das -D-Argument in der Java-Befehlszeile oder über einen System.setProperty-Methodenaufruf festgelegt werden.

Angeblich werden diese von der Implementierung zwischengespeichert, so dass Sie sie nicht von einer Sache zur anderen ändern können, so dass sie einmal verwendet werden, die Werte bleiben erhalten.

Auch funktionieren sie nicht wirklich für SSL-Verbindungen ala HttpsURLConnection. Es gibt andere Möglichkeiten, mit einer benutzerdefinierten SSLSocketFactory umzugehen.

Auch dies gilt für JVM 1.4.x. Um 1.5 und höher haben Sie mehr Möglichkeiten in der API zur Verfügung (wie von den anderen Responder oben erwähnt).

1

Für Java 1.4, Sie SimpleHttpConnectionManager.getConnectionWithTimeout (hostConf, connection_timeout) von Apache