Sockets - Checking For Dropped Connections & close()

J

JTeagle

What is the correct way to determine if a socket to which you were
connected has been closed, either by implicitly calling close() on it,
or because the code that created it has been terminated?

This, for example, does not do what I believe it should:

import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JOptionPane;

public class TestSocketCloseApp
{
public static void main(String[] args)
{
try
{
// Create a listening socket.
ServerSocket listener = new ServerSocket(9999);

// Create a client socket and initiate a connection.
Socket client = new
Socket(InetAddress.getLocalHost().getHostAddress(), 9999);
// Stop it from lingering - when we say close, we mean close.
client.setSoLinger(false, 0);

// Accept a connection from this client socket.
Socket server = listener.accept();

// Now close the client connection.
client.close();

// What does the server say our state is?
if (server.isConnected() )
JOptionPane.showMessageDialog(null,"Apparently we're still
connected.");
else
JOptionPane.showMessageDialog(null,"As expected, we're
disconnected.");

server.close();
listener.close();
}
catch(Exception e)
{
}
}

}


It still thinks it's connected when I clearly closed the other end.

I have tried other options in my original code - grabbing the output
stream and sending data (that didn't fail, even though there should be
no link), trying to request the remote address we are connected to -
they all work as if we are still connected.

Does close() not do what it claims? I would say it's fairly
fundamental of any program that deals with socket connections to know
when the other end has dropped.
 
G

Gordon Beaton

What is the correct way to determine if a socket to which you were
connected has been closed, either by implicitly calling close() on
it, or because the code that created it has been terminated?

When isConnected() is true, it only indicates that s.connect() has
been called at some previous time. It says nothing about the state of
the underlying socket itself.

To determine whether the socket has been closed, attempt to read()
from it or write() to it. Either of these operations will indicate EOF
(exactly how depends on which class you use to read or write).

/gordon

--
 
G

Gordon Beaton

What is the correct way to determine if a socket to which you were
connected has been closed, either by implicitly calling close() on it,
or because the code that created it has been terminated?

I find it interesting that you asked the exact same question exactly 4
years (plus one day) ago. It was answered then, but you seem to be
making the same mistakes again.

/gordon

--
 
J

JTeagle

I find it interesting that you asked the exact same question exactly 4
years (plus one day) ago. It was answered then, but you seem to be
making the same mistakes again.

/gordon

--

I guess that means the API is still badly named - if there were
functions that actually did what they claim in the name, we wouldn't
be here again.

Not sure how you found that previous message - even I hadn't
remembered that - it's been that long since I did any Java. Pity the
API hasn't improved much since then.

The problem with doing a read is that if the socket hasn't closed, you
end up blocking - it defeats the purpose of a 'test' to see if the
socket is closed. The problem with a write is that you end up writing
spurious data out to the socket. If the implementation can tell (when
you read or write) that the network has been lost, why can't it do so
to provide a proper test method - hasRemoteSocketClosed(), for
example?

Sorry that I brought the same question back.
 
G

Gordon Beaton

I guess that means the API is still badly named - if there were
functions that actually did what they claim in the name, we wouldn't
be here again.

The methods are poorly named, but they do work as documented.
Not sure how you found that previous message - even I hadn't
remembered that - it's been that long since I did any Java. Pity the
API hasn't improved much since then.

I recognized the question, and the asker...
The problem with doing a read is that if the socket hasn't closed, you
end up blocking - it defeats the purpose of a 'test' to see if the
socket is closed. The problem with a write is that you end up writing
spurious data out to the socket. If the implementation can tell (when
you read or write) that the network has been lost, why can't it do so
to provide a proper test method - hasRemoteSocketClosed(), for
example?

The socket interface provided by the OS works that way, and in that
respect there is no difference reading from any kind of descriptor,
regardless of the underlying structure (file, pipe, socket, character
device, etc). Not all of these interact with a remote that actively
closes the other end.

Note too that the remote may have closed while you have remaining
unread data, in which case you don't actually reach EOF until you've
read to the end of the data stream.

If you don't want to risk blocking, use a Selector. It provides the
necessary test, and will tell you when you can safely read *without*
blocking.

/gordon

--
 
J

JTeagle

The methods are poorly named, but they do work as documented.

The docs are a bit lacking in that respect - they need to make the
distinction between "is currently connected" and "has connected at
some moment in the past" clear for new programmers, but I accept your
point.
I recognized the question, and the asker...

I guess I should worry about that in my spare time! {:v)
Note too that the remote may have closed while you have remaining
unread data, in which case you don't actually reach EOF until you've
read to the end of the data stream.

That's a very valid point. My initial problem was that available() on
the BufferedInputStream() returns 0 even when disconnected, which is
fairly logical but not helpful - this prompted me to look more
closely.
If you don't want to risk blocking, use a Selector. It provides the
necessary test, and will tell you when you can safely read *without*
blocking.

Unfortunately that doesn't help - I'm assuming that's similar to
available(), which as mentioned above returns 0 for the disconnected
case (technically, there are 0 bytes you can read from a closed socket
without blocking), which doesn't hint that the connection has been
lost.

I did eventually realise, however, that I can use setSoTimeout() on
the socket to minimise blocking time.

Thanks for your thoughts.
 
G

Gordon Beaton

Unfortunately that doesn't help - I'm assuming that's similar to
available(), which as mentioned above returns 0 for the disconnected
case (technically, there are 0 bytes you can read from a closed
socket without blocking), which doesn't hint that the connection has
been lost.

A Selector can tell you when it's safe to read without blocking.
Actually reading is still necessary to tell you whether there was data
to read, or you're at EOF. A single Selector can be used to monitor
many existing and arriving connections simultaneously for connecting,
accepting, reading or writing, according to which SelectionKeys you've
registered interest in.

InputStream.available() tells you how much data has arrived and is
waiting to be read on a single InputStream. It can't tell the
difference between EOF and "currently no data", so reading might still
block.

/gordon

--
 
J

JTeagle

A Selector can tell you when it's safe to read without blocking.
Actually reading is still necessary to tell you whether there was data
to read, or you're at EOF. A single Selector can be used to monitor
many existing and arriving connections simultaneously for connecting,
accepting, reading or writing, according to which SelectionKeys you've
registered interest in.

InputStream.available() tells you how much data has arrived and is
waiting to be read on a single InputStream. It can't tell the
difference between EOF and "currently no data", so reading might still
block.

OK... I'll look into trying a Selector. Thanks.
 
L

Lew

JTeagle said:
The docs are a bit lacking in that respect - they need to make the
distinction between "is currently connected" and "has connected at
some moment in the past" clear for new programmers, but I accept your
point.

Blame the docs, blame the language, but by no means blame yourself.

Here's what the docs say:
true if the socket successfuly connected to a server

We look at your code and see that the socket successfully connected to a
server. Working as advertised. Nothing there says the socket still has to be
connected. Yep, still working as advertised.
 
T

Thomas Schodt

Lew said:
Blame the docs

Rather than blaming the docs, suggest an improvement.


bool Socket.isConnected()
Indicates if connect() has been called on this socket.
Initially this method returns false. After a connection is established,
this method method returns true. It will never change back to false for
any reason (like the connection failing).

bool Socket.isClosed()
Indicates if close() has been called on this socket.
Initially this method returns false. After Socket.close() is invoked
this method returns true. It will not return true for any other reason
(like the connection being closed by the remote end).
 
E

Esmond Pitt

JTeagle said:
// Stop it from lingering - when we say close, we mean close.
client.setSoLinger(false, 0);

Don't do this. Don't even think about doing it unless (i) you're
prepared to lose the last piece of data you wrote, and (ii) you're
prepared to read data on the next connection that may not belong to you.

TCP/IP has the TIME-WAIT state for a very good reason. Don't break it.
 
R

Richard Maher

Hi Esmond,
and (ii) you're
prepared to read data on the next connection that may not belong to you.

Is there an example of this on the web somewhere? Peculiar to Java?

Cheers Richard Maher
 
E

Esmond Pitt

Richard said:
Is there an example of this on the web somewhere? Peculiar to Java?

Any 'example' would consist of a misbehaving application, not a piece of
code, and it has nothing to do with Java. It's discussed in the TCP/IP
RFCs.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top