Solved

timout on readLine

Posted on 2000-04-12
16
390 Views
Last Modified: 2008-03-06
Hello,
   How would you write java code to timeout on a call to BufferedReader.ReadLine() ?

I would like to make the call and if nothing comes back in a minute then terminiate the read.


0
Comment
Question by:calvinrsmith
  • 6
  • 4
  • 3
  • +2
16 Comments
 
LVL 16

Accepted Solution

by:
imladris earned 9 total points
Comment Utility
Do the readLine in a separate thread. Then, when the main thread has waited long enough, it can carry on. It may want to kill the "read" thread. This can be done with the stop method, or (since stop has been deprecated in 1.2) by calling interrupt and the read thread catching the InterruptedException.
0
 
LVL 5

Expert Comment

by:mbormann
Comment Utility
readymade code,pls look and use it...
Notice that this code is JDK1.2 compliant ,I am closing the underlying InputStream in ,so

if you have to close the socket read/write
you have to close() the underlying input/output stream.
Get a reference like
InputStream in=sock.getInputStream();
Use in program like
BufferedReader buff = new BufferedReader(new InputStreamReader(sock.getInputStream()));

The reason is that both read() and close() are synchronized in
Wrapper classes like BufferedReader & BufferedInputStream in JDK 1.2
& up ,so this above program will only work in JDK 1.1.

Translated into simpler terms when you call close() ,it will block
forever.

So use

in.close() instead of buff.close()

public class AsyncReadBuffer
{
    private StringBuffer result;

    public AsyncReadBuffer()
    {
        result = new StringBuffer(500);
    }

    //Get the string already read from the socket so far.
    //This method is used by the Applet or external thread
    //to obtain the data in a synchronous manner.
    public synchronized String getResult()
    {
        String retval = result.toString();
        result.setLength(0);
        return retval;
    }

    //Put new data into the buffer to be returned
    //by the getResult method
    public synchronized void update(char c)
    {
        result.append(c);
    }

public synchronized void update(String s)
    {
        result.append(s);
    }
}


import java.util.*;
import java.io.*;
import java.net.*;

public class ClientHandler extends Thread
{
    private InputStream in;
    private BufferedReader buff;
    private Socket sock;
    private AsyncReadBuffer aReader;
    private boolean isDone = false;
    private Object lock = new Object();
private int timeout;
private boolean isReadLineMode=false;

    class ClientHandlerThread extends Thread
    {
        public void run()
        {
            String s;
int c;
            try
            {
if(isReadLineMode)
{
while ((s = buff.readLine()) != null)
    aReader.update(s);
}
else
{
while ((c = buff.read()) != -1)
    aReader.update((char)c);
}
}
            catch (Exception e)
            {}

            isDone = true;
            synchronized(lock)
            {
                lock.notify();
            }
        }
    }

    public ClientHandler(AsyncReadBuffer a, Socket s,int t,boolean isReadLine)throws Exception
    {
this.aReader=a;
        this.sock=s;
this.isReadLineMode=isReadLine;
if(t<0 || t==Integer.MAX_VALUE)
throw new Exception("Specify correct timeout value");
this.timeout=t;
    }

    public void run()
    {
try
{
    in=sock.getInputStream();
    this.buff = new BufferedReader(new InputStreamReader(in));
    Thread t = new ClientHandlerThread();
    t.start();
    synchronized(lock)
    {
        while (!isDone)
        {
            try
            {
                lock.wait(this.timeout);
            }
            catch (InterruptedException ie)
            {
                isDone = true;
                try
                {
                    t.interrupt();
                    this.in.close();this.in=null;
                    this.sock.close();this.sock=null;
                }
                catch (Exception e)
                {}
            }
        }
    }
}
catch(Throwable t)
{
System.out.println("Caught Exception during run() in timeout main thread");
t.printStackTrace();
}
}
}
0
 
LVL 19

Expert Comment

by:Jim Cakalic
Comment Utility
I've been working on trying to find a non-threaded solution. After a good bit of experimentation, I determined that the code appearing below SHOULD work. Unfortunately, it does not work on win32 systems because the BufferedReader implementation -- at least in jdk1.3rc2 -- does not correctly (or at least to my liking) implement the semantics of readLine().

The API docs for readLine state: "Read a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed." This gives one (one being me in this case) the impression that the entire line-termination sequence will consumed. On win32 systems, line-termination is "\r\n", two characters. Unfortunately, the implementation does not consume both characters immediately. It finds the carriage return but leaves the newline in the buffer. As a result, ready() returns true but the subsequent read blocks when the only content in the buffer is the second half of the win32 line termination sequence.

This same problem does not appear to plague the InputStreamReader so it would be possible to use the technique implemented below with that reader. Perhaps I should provide a readLine() implementation for InputStreamReader? If anyone is interested, let me know.

Here is the correct but, on win32 systems, non-working code:

---------- TimedReader.java ----------
import java.io.InputStreamReader;
//import java.io.BufferedReader;
import java.io.Reader;
import java.io.IOException;

public class TimedReader {
    public static void main(String[] args) {
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader in = new BufferedReader(isr);
        while (true) {
            try {
                System.out.print("Enter a String: ");
                if (ready(in, 5000)) {
                    String s = in.readLine();
                } else {
                    System.out.println("timeout");
                }
            } catch (IOException e) {
                // ignore until we know what to do
            }
        }
    }

    public static boolean ready(Reader in, long timeout) throws IOException {
        while (true) {
            long now = System.currentTimeMillis();
            try {
                while (in.ready() == false && timeout > 0) {
                    Thread.sleep(100);
                    timeout -= 100;
                }
                return in.ready();
            } catch (IOException e) {
                throw e;
            } catch (Exception e) {
                // ignore
            } finally {
                // adjust timer by length of last nap
                timeout -= System.currentTimeMillis() - now;
            }
        }
    }
}
---------- end ----------

Since you didn't state your platform, this code may work just fine for you. I hope so. I have a modified version of BufferedReader.java which fixes the problem -- but I don't know how robust that fix is or whether it would prevent this scenario in all circumstances.

Best regards,
Jim Cakalic
0
 
LVL 5

Expert Comment

by:mbormann
Comment Utility
I think Jim ur code would work on JDK 1.2.2 ,what do you think ?

Have they introduced a bug in JDK1.3?
0
 
LVL 19

Expert Comment

by:Jim Cakalic
Comment Utility
Amit, if you have a previous version of the JDK, would you care to give it a try? I only have 1.3 at my disposal presently.

You may be right, though, about changed behavior. In Harold's Java I/O book from O'Reilly, he states that BufferedReader.readLine() has "the potential to hang on a long carriage return that ends the stream. This problem is especially acute on networked connections, where readLine() should never be used." Browsing the bug database at JDC, I found quite a few complaints about the hanging carriage return problem. Perhaps they introduced a 'fix' in 1.3. Again, I don't have what I need to check this out so any help would be appreciated.

Jim
0
 
LVL 19

Expert Comment

by:Jim Cakalic
Comment Utility
Just realized that, since I have JBuilder 3 I have jdk1.2.2 installed. Found the source and the code for BufferedReader.readLine() has been changed. Compiled and tested the old code with my program above and it works!!!!! I'm not going crazy after all.

Guess I'll post something on the bug parade. Doubt if it will get into jdk1.3, though. They're already in rc2.

Jim
0
 
LVL 1

Author Comment

by:calvinrsmith
Comment Utility
  I'm still using JDK1.1.8 I'll give the above ideas a try and let you know what I find.  
0
 
LVL 5

Expert Comment

by:mbormann
Comment Utility
calvinrsmith,
Oops sorry I realized that I had cut-pasted wrong explanation in my long comment above. But the code is perfect. You can use that too .

But I think u would be happy with Jim's solution.
:)

Jim , it works. And I will post this code sometime later today to the question from which I cut-pasted the original code.

Cheers fellows
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 19

Expert Comment

by:Jim Cakalic
Comment Utility
Those guys at Sun are fast. I submitted a bug report this afternoon and already got back a reply that it is considered to be a new defect and has been assigned id 4329985. It may not show up on the bug parade for several days according to the email I received.
0
 
LVL 5

Expert Comment

by:mbormann
Comment Utility
Wow ! Yes I also reported a 'bug' but it was submitted just sometime b4 I sent them a mail and they gave the same reply.

They work round the clock is what I think,must be having guys all over the world in differect time zones.

Cheers Jim
0
 
LVL 1

Author Comment

by:calvinrsmith
Comment Utility
jim_cakalic,
  I tested your code with jdk1.1.8 on win98 and found that in.ready() always returns true, even if your ready function just started.
0
 
LVL 19

Expert Comment

by:Jim Cakalic
Comment Utility
Calvin, I don't know what to tell you about this other than jdk1.1.8 is notoriously buggy. Running in win95 or win98 doesn't help. Is it possible for you to use a more recent release of the jdk? Any of the 1.2 releases would be better. Frankly, many suggestions I have seen are to stick with 1.1.7 if 1.2 is not an option.

I've got IBM's port of 1.1.8 to AIX that I can look at. Barring that, I'd have to download and unpack (if not install) another jdk version. Painful but I'd consider doing it.

Anybody else have any ideas?
Jim
0
 

Expert Comment

by:leach072899
Comment Utility
I checked this code on VisualAge with JDK 1.1.7 - works perfectly.
0
 
LVL 19

Expert Comment

by:Jim Cakalic
Comment Utility
Hi, leach.

This one has certainly been around for awhile, hasn't it? Thanks for testing it. I figured Calvin had abandoned the question. Looked on the JDC and the bug has 21 votes but apparently never got fixed in the 1.3 release.

Jim
0
 

Expert Comment

by:leach072899
Comment Utility
Hi Jim,
Well it was about something i was looking for.
Moving to Java 2 (any version) looks a bit farther then i want it to be, for us VisualAge users.
My problem is a bit more trickier so i opened another question on it - see if you can answer.

lee
0
 

Expert Comment

by:leach072899
Comment Utility
I said it runs with JDK 1.1.7 - i must retrackt that.
At least on the IBM implementation the timeout works perfectly when needed - but when all is well - using the timeout after the connection was closed (from either end) will result in a timeout condition. And there is no way (that i found yet) to distinguish the two cases: timeout and connection closed.

lee
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

For customizing the look of your lightweight component and making it look lucid like it was made of glass. Or: how to make your component more Apple-ish ;) This tip assumes your component to be of rectangular shape and completely opaque. (COD…
After being asked a question last year, I went into one of my moods where I did some research and code just for the fun and learning of it all.  Subsequently, from this journey, I put together this article on "Range Searching Using Visual Basic.NET …
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…
Viewers will learn about the different types of variables in Java and how to declare them. Decide the type of variable desired: Put the keyword corresponding to the type of variable in front of the variable name: Use the equal sign to assign a v…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now