Socket / ServerSocket & Remote Disconnection Detecting

J

Jason Teagle

If a client Socket makes a connection to a ServerSocket, and then
disconnects from it, how can code from the ServerSocket side detect that
disconnection?

Similarly, if the ServerSocket closed down the client's connection, how can
code from the client side detect that disconnection?

I had some code that was failing, so I generated a new crude test
application. In the server side, I call isClosed() on the server socket
every 10th of a second, to see if it is still open. Sure enough, when I
disconnect the client side deliberately, the server side continues to claim
that it is connected.

Just in case it was my code that was naff even in the test app, I used
breakpoints to make sure it was getting to the check and never to the
disconnect detection.

--
Jason Teagle
(e-mail address removed)


The demo is reproduced below, if anyone is interested (click "Start server",
then "Connect client", then "Disconnect client" - the console should say "It
was closed." if it detects the disconnection):


import java.io.IOException;
import java.net.ServerSocket;
import java.util.Timer;
import java.util.TimerTask;

/**
* @author Jason Teagle
*
*
*/
public class JServerSocket extends ServerSocket
{
private Timer m_timer ;
private TimerTask m_task ;

public JServerSocket(int portNumber) throws IOException
{
super(portNumber, 5);

try
{
m_task = new TimerTask()
{
public void run()
{
checkStatus();
}
};
m_timer = new Timer();
m_timer.schedule(m_task, 100, 100);
}
catch(Exception e)
{
System.out.println("Couldn't create server socket.");
}
}

private void checkStatus()
{
if (isClosed() )
System.out.println("It was closed.");
}

}



-----------------------------------------------------------



import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

/**
* @author Jason Teagle
*
*
*/
public class JClientSocket extends Socket
{
public JClientSocket(int portNumber)
{
super();

SocketAddress addr ;

addr = new InetSocketAddress("127.0.0.1", portNumber);
try
{
connect(addr, 1000);
}
catch(Exception e)
{
System.out.println("Failed to connect.");
}
}

public void disconnect()
{
try
{
close();
}
catch(Exception e)
{
}
}

}




-----------------------------------------------------------



import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JFrame;

/**
* @author Jason Teagle
*
*
*/
public class JMainFrame extends JFrame
{
public static void main(String[] args)
{
JMainFrame mainFrame = new JMainFrame();
mainFrame.setVisible(true);
mainFrame.pack();
}

private JServerSocket m_server ;
private JClientSocket m_client ;

public JMainFrame()
{
super("TestSocketDisconnect");

Container contentPane ;
JButton button ;

m_server = null ;
m_client = null ;

contentPane = getContentPane();
contentPane.setLayout(new GridLayout(3, 1) );

button = new JButton("Start server");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
startServer();
}
}
);
contentPane.add(button);

button = new JButton("Connect client");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
connectClient();
}
}
);
contentPane.add(button);

button = new JButton("Dicsonnect client");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
disconnectClient();
}
}
);
contentPane.add(button);

addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
);
}

private void startServer()
{
if (m_server == null)
{
try
{
m_server = new JServerSocket(1234);
}
catch(Exception e)
{
System.out.println("Unable to construct server socket.");
}
}
}

private void connectClient()
{
if (m_client == null)
m_client = new JClientSocket(1234);
}

private void disconnectClient()
{
if (m_client != null)
{
m_client.disconnect();
m_client = null ;
}
}

}
 
J

Jason Teagle

The demo is reproduced below, if anyone is interested (click "Start
server",
then "Connect client", then "Disconnect client" - the console should say "It
was closed." if it detects the disconnection):

OK, that was a little embarrassing - the code for the server socket was not
even calling accept(), which is a bit silly of me. In my defence, the actual
code of mine that was failing was the client end, so it DID call isClosed()
and did NOT need to accept anything {:v)

But even when I do call accept() correctly as I should, and call
isConnected() rather than isClosed(), it still NEVER detects the
disconnection.

Help?

Here's the corrected code for the server socket:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;

/**
* @author Jason Teagle
*
*
*/
public class JServerSocket extends ServerSocket
{
private Socket m_otherSocket ;
private Timer m_timer ;
private TimerTask m_task ;

public JServerSocket(int portNumber) throws IOException
{
super(portNumber, 5);

try
{
m_task = new TimerTask()
{
public void run()
{
checkStatus();
}
};
m_timer = new Timer();
m_timer.schedule(m_task, 100, 100);
}
catch(Exception e)
{
System.out.println("Couldn't create server socket.");
m_otherSocket = null ;
m_timer = null ;
m_task = null ;
}
}

private void checkStatus()
{
if (m_otherSocket == null)
{
try
{
// First time we hit here, we actually start listening. This
// won't allow the timer thread to continue until a client
// actually connects, THEN it starts checking the connection
// status (confirmed by breakpoints).
m_otherSocket = accept();
}
catch(Exception e)
{
}
}
if (m_otherSocket != null && !m_otherSocket.isConnected() )
{
// Never gets here.
System.out.println("It was closed.");
}
}

}
 
G

Gordon Beaton

If a client Socket makes a connection to a ServerSocket, and then
disconnects from it, how can code from the ServerSocket side detect
that disconnection?

Similarly, if the ServerSocket closed down the client's connection,
how can code from the client side detect that disconnection?

The ServerSocket is never connected to the (client) Socket.
ServerSocket.accept() returns a new Socket, i.e. the resulting
connection is between two Sockets.

The ServerSocket and resulting Socket are completely distinct and have
nothing to do with each other's subsequent state, so either one can
close without affecting the other. More specifically, the ServerSocket
cannot detect when one of "its" Sockets have closed.

The only way to check for disconnection is to read from or write to
the Socket (through one of its streams). This doesn't apply to
ServerSockets, which are never connected.

isClosed() can only be used to detect if the corresponding close()
method has been called. The documentation doesn't define "the closed
state" but the library source is clear enough.

/gordon
 
J

Jason Teagle

isClosed() can only be used to detect if the corresponding close()
method has been called. The documentation doesn't define "the closed
state" but the library source is clear enough.

What about Socket's isConnected() method (if called on one of the sockets
that results from accept(), which you'll see I realised about 10 minutes
later)? That seems to be giving bogus information after the client has
disconnected from it.
 
S

Sajjad Lateef

If a client Socket makes a connection to a ServerSocket, and then
disconnects from it, how can code from the ServerSocket side detect that
disconnection?

On the server side, when you call accept() on the ServerSocket, you will
get a Socket object. You will want to put all reads and writes to the
Socket object in a try{} block and catch any IOException that is raised.

If the socket connection has been closed from the client side, you
will detect the disconnection with the code in the catch(IOException ioe)
block.

The ServerSocket object is no longer involved after the accept() and
all future communication is the responsibility of the Socket object
on the server side.
Similarly, if the ServerSocket closed down the client's connection, how can
code from the client side detect that disconnection?

Similiar to above, put all reads and writes to the Socket in a try block
and catch(IOException ioe) code will be invoked when the socket connection
is disconnected from the server side.

Sajjad
 
G

Gordon Beaton

What about Socket's isConnected() method

It just tells you whether the Socket has been connected at some time.
In other words, it tells you that that the Socket was created in the
connected state or that connect() has been successfully called. It
says nothing about the actual state of the Socket.

Although the method's API documentation could be much clearer, it does
say "true if the socket successfully connected to a server", not "is
connected to a server". The source code verifies what is meant.

Once again, the only way to determine whether the Socket really is
connected is to read from or write to it.

/gordon
 
S

Shripathi Kamath

Jason Teagle said:
If a client Socket makes a connection to a ServerSocket, and then
disconnects from it, how can code from the ServerSocket side detect that
disconnection?

Similarly, if the ServerSocket closed down the client's connection, how can
code from the client side detect that disconnection?

I had some code that was failing, so I generated a new crude test
application. In the server side, I call isClosed() on the server socket
every 10th of a second, to see if it is still open. Sure enough, when I
disconnect the client side deliberately, the server side continues to claim
that it is connected.

Just in case it was my code that was naff even in the test app, I used
breakpoints to make sure it was getting to the check and never to the
disconnect detection.


<snip>

I presume that you mean the socket on the server side that is connected (via
an accept() on the ServerSocket) to the client socket.

Unless there is an attempt to read or write, it is not possible under TCP to
detect a broken or closed connection.

In other words, a broken or closed connection looks the same as a quiet
connection.

Typically, if one has control over the protocol, one can arrange to have
some periodic traffic (some read and write activity) over the virtual
circuit so that an Exception may be generated when trying to communicate.

Some network cards can detect if the other end has been disconnected, and
depending upon your OS and drivers, this is conveyed up to the TCP stack
(and therefore the Java socket) via an exception. This is not universal,
but can be used in some applications where the situation is well-controlled.

HTH,
 
R

Roedy Green

the server side continues to claim
that it is connected.

Quiet sockets don't send packets back and forth do they, even with
keepalive?

You can send heartbeat packets back and forth at the application level
that let you know the connection is still alive. This is what I have
done without problem.
 
J

Jason Teagle

You can send heartbeat packets back and forth at the application level
that let you know the connection is still alive. This is what I have
done without problem.

This only works if you control the server and client sides, and thus can
arrange for such packets to pass back and forth harmlessly. If you're
working with a server using an established protocol such as FTP or HTTP,
this isn't feasible since the server would attempt to parse whatever you
send and you don't want that erroneous data. Waiting until you have
something genuine to send may be too late to find out. Imagine if you're
listening for incoming data from a (read-only) device that is sending
periodic data to you - if it goes silent, is that because it just doesn't
have any more data to send right now or because the connection was lost?

There MUST be a way to test it (maybe not in Java), otherwise Visual C++'s
CAsyncSocket wouldn't be able to tell you the connection had dropped, and I
know Delphi can do it also (I've tried to find info on this by Googling, and
caught some similar articles).

I hate Java's "just try to use it and see if it breaks" attitude (grumble,
grumble) {:v)
 
E

EJP

Read with a timeout or use Selector.select(). There is no other way in
Java because there is no other way in TCP/IP.
 
J

Jason Teagle

Read with a timeout or

No good as a test. If the connection is live and data is available, it will
read the data available. This is thus not a test, it's an actual read (I
refer you back to my rambling speech about finding out during an actual read
/ write being too late).
use Selector.select().

This looks interesting - I might play around with this.
because there is no other way in TCP/IP.

If the mighty MS can do it with their CAsyncSocket, I'm sure Java can do it,
if they tried. Surely Sun don't want to be outdone by the alleged root of
all evil? {:v)
 
E

EJP

MS do it with select(). There are no other ways.

Jason said:
No good as a test. If the connection is live and data is available, it will
read the data available. This is thus not a test, it's an actual read (I
refer you back to my rambling speech about finding out during an actual read
/ write being too late).


This looks interesting - I might play around with this.


If the mighty MS can do it with their CAsyncSocket, I'm sure Java can do it,
if they tried. Surely Sun don't want to be outdone by the alleged root of
all evil? {:v)
 

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,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top