tags:

views:

3460

answers:

5

I want to read the contents of a URL but don't want to "hang" if the URL is unresponsive. I've created a BufferedReader using the URL...

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

...and then begun the loop to read the contents...

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

...but if the read hangs then the application hangs.

Is there a way, without grinding the code down to the socket level, to "time out" the read if necessary?

+7  A: 

I think URLConnection.setReadTimeout is what you are looking for.

jsight
Awesome, thank you. Added in 1.5!
dacracot
A: 

@m_PGladiator

I should have clarified this... I do have a thread that kills the process if it runs over, but in my optimization, I've found it to be one of the biggest time consumers. I was hoping for a more efficient solution that may not have been thread based. Perhaps there is no other.

dacracot
+2  A: 

Since Java 1.5, it is possible to set the read timeout in milliseconds on the underlying socket via the 'setReadTimeout(int timeout)' method on the URLConnection class.

Note that there is also the 'setConnectTimeout(int timeout)' which will do the same thing for the initial connection to the remote server, so it is important to set that as well.

Pete
Doesn't openConnection() start the connection, so would setting the open connection timeout have an effect or does it read the value even after it started the connection process?
William
+2  A: 

If you have java 1.4:

I assume the connection timeout (URLConnection.setConnectTimeout(int timeout) ) is of no use because you are doing some kind of streaming.

---Do not kill the thread--- It may cause unknown problems, open descriptors, etc.

Spawn a java.util.TimerTask where you will check if you have finished the process, otherwise, close the BufferedReader and the OutputStream of the URLConnection

Insert a boolean flag isFinished and set it to true at the end of your loop and to false before the loop

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

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

This will probably cause an ioexception, so you have to catch it. The exception is not a bad thing in itself. I'm omitting some declarations (i.e. finals) so the anonymous class can access your variables. If not, then create a POJO that maintains a reference and pass that to the timertask

Javaxpert
That's a nice solution, but I think your task will only fire once. That would probably fail for a long term transfer process, thus it would be better to run on an interval and stop the timer when done. Interesting idea, though.
jsight
+1  A: 

I have been working on this issue in a JVM 1.4 environment just recently. The stock answer is to use the system properties sun.net.client.defaultReadTimeout (read timeout) and/or sun.net.client.defaultConnectTimeout. These are documented at Networking Properties and can be set via the -D argument on the Java command line or via a System.setProperty method call.

Supposedly these are cached by the implementation so you can't change them from one thing to another so one they are used once, the values are retained.

Also they don't really work for SSL connections ala HttpsURLConnection. There are other ways to deal with that using a custom SSLSocketFactory.

Again, all this applies to JVM 1.4.x. At 1.5 and above you have more methods available to you in the API (as noted by the other responders above).

Chris Markle