Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Java, why does readLine() block on a closed socket connection?

I have a simple Client/Server app. The server is set up so that if no data comes in within N seconds a timeout occurs and the socket connection is closed. I do this via Socket.setSoTimeout(). That all works fine if the client hangs. If the clients dies, though (e.g. I kill it with Ctrl-C), then readLine() never times out.

Here's the server code, if that makes a difference:

public void run()
{
    PrintWriter out = null;
    BufferedReader in = null;

    try {
        sock.setSoTimeout(10000);

        out = new PrintWriter(sock.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

        String input;
        while ((input = in.readLine()) != null) {

I've tried putting in a signal handler into the client to send an ABEND message over to the server but that's not working (I suspect the socket gets closed before the ABEND is sent, but I haven't really spent any time trying to figure that out).

Is there a way to wake up periodically and check the socket state to see if it's closed? Or (better yet) not have readLine() hang if the socket closes? Should I be using an unbuffered reader of some sort? Does an unbuffered reader supporting a readLine-like mechanism exist?

I am using Java 6 on Linux.

EDIT: I'm killing the client myself during an idle period; all data has been sent and received at this point. I have verified (via ps) that the client program is no longer running; the Java process has indeed been killed. Using netstat I can see that the socket is closed, on both ends, yet readLine() still hangs.

like image 398
Joe Casadonte Avatar asked Feb 07 '13 13:02

Joe Casadonte


1 Answers

I think you have misdiagnosed the problem.

If the input side of the socket has been closed, then the readLine() call should see that close. After all buffered data has been consumed, the call should return a null. (You won't get an IOException if the socket is closed normally, but you could get one if the connection times out ... for example.)

The most obvious explanation is that the socket has not been closed yet. Take a look at the circumstances in which the other end will close the socket, and figure out why this hasn't happened yet.


None of these is the solution, but I'll answer for completeness.

Is there a way to wake up periodically and check the socket state to see if it's closed?

Another thread could do that, but not this one.

Or (better yet) not have readLine() hang if the socket closes?

That's what is supposed to happen.

Should I be using an unbuffered reader of some sort?

It wouldn't help. You'd end up having to implement readLine() yourself, and your code would block at the same point. The blocking behaviour is happening below the buffering and character decoding layers of the reader chain.

Does an unbuffered reader supporting a readLine-like mechanism exist?

No it doesn't. See above.

like image 119
Stephen C Avatar answered Sep 28 '22 07:09

Stephen C