Link to home
Start Free TrialLog in
Avatar of Spoogi
Spoogi

asked on

BufferedReader.readLine() sometimes hangs my app

Hi all,

I have a java application that reads in the contents of a URL every 10 minutes. Basically:

...
BufferedReader in = new BufferedReader( new InputStreamReader(conn.getInputStream()));
String s=null;
System.out.println("about to use readLine()");
while ( (s=in.readLine()) != null) {
//do something
...

Everything works fine, until (at random intervals of several hours), my app just hangs at while ( (s=in.readLine()) != null)

When it 'hangs' it doesn't use any cpu time ... it just sits there for hours. I have to stop (ctrl c) and restart the program in order to get it working again.

Is there some condition that should be met before i attempt in.readLine()? Anything else that could cause this?

Thanks kindly
Ryan
Avatar of JNic
JNic

Can you post the code where conn is being defined?
Avatar of CEHJ
>>Anything else that could cause this?

Could be just network difficulties. Just trap and log any exceptions.
You could cast the URLConnection to HttpURLConnection and only proceed with getting a stream if HTTP_OK:

http://java.sun.com/j2se/1.4.2/docs/api/java/net/HttpURLConnection.html#HTTP_OK
Avatar of Spoogi

ASKER

Jnic:
                      URL url = new URL(newsfeedURL);
                      URLConnection conn = url.openConnection();
                      conn.setDoOutput(true);
                      PrintWriter pw = new PrintWriter( conn.getOutputStream());
                      pw.print("client_id=xxxxxxx");

CEHJ:

I am trapping all exceptions, and none is thrown in this case.  If the remote site is down, the exception (SocketException) is thrown & logged.

Thanks
Avatar of Spoogi

ASKER

CEHJ:

I'll try your suggestion.  I've inserted the following into my code prior to "while ( (s=in.readLine()) != null)":

                        HttpURLConnection httpConnection = (HttpURLConnection)conn;
                        int code = httpConnection.getResponseCode();
                        if (code != HttpURLConnection.HTTP_OK)
                        {
                           String message = httpConnection.getResponseMessage();
                           System.out.println(code + " " + message);
                           return;
                        } else {
                               System.out.println("HTTP_OK: "+code);
                        }

It's nothing but informative at this point, but will let me know what the response code is the next time the 'hang' happens.  Stay tuned, will probably take several hours for it to re-occur.

Thanks
OK - not sure if you need to print the OK code ;-)
Try reading the content with a stream instead of a reader and see if the problem still occurs. If it doesn't then simply convert the bytes read into a stream after they are read instead of having the reading handle the conversion.
Avatar of Spoogi

ASKER

More on this.  The HttpURLConnection is always OK.  It starts reading in lines of the bufferedreader, and then will sometimes just hang in the process.  No unusual characters in the document or anything, and never on the same document twice ... appears to be random to me.

objects:  I'm not entirely certain what you are suggesting ... I'll have to do a little research on how to read the content with a stream.

Thanks
>  I'm not entirely certain what you are suggesting

I meant instead of using a Reader, read the bytes directly from the stream.

InputStream in = request.getInputStream();
while (-1!=(in.read())
{
   // if this works then we can construct a String from the data read
}
Avatar of Spoogi

ASKER

Thanks for the code example objects.

May I ask why you suggest using a Reader may be causing the problem?  Would the following satisfy your hunch?

                            InputStream inStream=conn.getInputStream();
                            BufferedReader in = new BufferedReader( new InputStreamReader(inStream));

                            System.out.println("Starting to read in stream");
                            while ((inStream.read()!=-1) && ( (s=in.readLine()) != null)) {
                                System.out.println(s);
                            }

i.e: I've added the "(inStream.read()!=-1)".  
Prior to adding this, in the case of a lockup, I would most often see "Starting to read in stream" print to the terminal, and System.out.println(s) would not show.  So it must have something do to with (s=in.readLine()) ???  

I'm in kind of a touchy environment:
- the lockup takes several hours, if not days to occur
- the remote server only allows my client_id to access it at 10 minute intervals
- the xml newsfeeds I am pulling down drive other internal applications that are in production

cry me a river, I know, but because of that last point I'm hesitant to re-write my app.  If you think this latest change could make the difference then I'll let things run till the next lockup.  If you're not convinced my change will make the difference, then perhaps I'll re-write over the weekend to follow your suggestions more closely.  Any other ideas would be helpful.

Thanks again

PS- I've heard a suggestion of using another thread to monitor this one and interject if it 'hangs' for a while.  I'm not sure if that's a good idea, or even how to do it.
> May I ask why you suggest using a Reader may be causing the problem?

Am just trying to simplify the process to better determine the cause.

> Would the following satisfy your hunch?

Not really, cause a Reader is still involved.


You could try and use a different http implementation instead of URLConnection.
Such as HTTPClient.
Does the server specify the http content length?

Using the stream approach I suggested above would allow you to determine at how many bytes had been read when it hangs which may give some clues.
ASKER CERTIFIED SOLUTION
Avatar of Mick Barry
Mick Barry
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Spoogi

ASKER

HTTPClient looks promising:

       setTimeout(int time)
                 Sets the timeout to be used for creating connections and reading responses.

I'm working on implementing right now.
Thanks
You can set timeouts as follows (or if you prefer, using System.setProperty in your code):

java -Dsun.net.client.defaultConnectTimeout=30000 -Dsun.net.client.defaultReadTimeout=30000

if these are exceeded, an exception will be thrown, allowing you to wait until later to try again
Avatar of Spoogi

ASKER

Objects:  I accepted your answer. HTTPClient does a fantastic job.  Thank you

CEHJ: Thank you as well.  I would have preferred to use your 'pure sun' solution.  But alas, now that the duct tape is holding I must move on to other things.  I'm definitely going to remember your timeout solution the next time....
...always a good idea to restrict yourself to the standard libraries if possible. And a points split might have been nice ..;-)
Avatar of Spoogi

ASKER

:-O  Sorry - didn't realize I had the option!