I have a listening port on my server that I'm connecting to using a Java class and the Socket interface, i.e.
Socket mySocket = new Socket(host,port);
I then grab an OutputStream, decorate with a PrintWriter in autoflush mode and I'm laughing - except if the listening port closes. Then I get
tcp4 0 0 *.9999 *.* LISTEN
tcp 0 0 127.0.0.1.45737 127.0.0.1.9999 CLOSE_WAIT
and I can't seem to detect the problem in the program - I've tried using the isConnected() method on the socket but it doesn't seem to know that the connection is closed.
I want to be aware of the problem the next time I try and write to the Socket so that I can try and reconnect and report the issue.
Any advice please?
Thanks all
Set a short timeout?
Does isOutputShutdown() not get you what you want?
You could always build a SocketWatcher class that spins up in its own Thread and repeatedly tries to write empty strings to the Socket until that raises a SocketClosedException.
The only reliable way to detect a broken connection in TCP is to write to it, which will eventually cause a 'connection reset' IOException. However due to buffering it won't happen on the first write after the disconnection,p but on a subsequent write. You can't do anything about this.
Set a different thread to reading from the socket. It will block until the socket is closed, and then an exception will be thrown. Catch that exception to detect the close immediately.
Related
Not able to detect a socket close. Not receiving -1 when reading with inputStream. I am thinking about disconnecting in case of SocketTimeoutException and trying to connect the socket again. How feasible would that be?
socket.setSoTimeout(100);
InputStream dis = socket.getInputStream();
int count =0;
try {
LogManager.logInfo("Inside read thread before reading");
count = dis.read(buffer); // not receiving -1 in case of socket close
} catch (SocketTimeoutException e) {
LogManager.logError("Socket timedout",e);
// should i try to reconnect to socket here
}
Not able to detect a socket close.
You haven't closed the socket, so there is nothing to detect. What you no doubt mean is 'not able to detect connection close', which is signalled by read() returning -1, readLine() returning null, or readXXX() throwing EOFException for any other XXX. I don't see any code here that tests this.
Not receiving -1 when reading with inputStream.
If the socket was closed you would get SocketException: socket closed. If the connection was closed you would get the behaviour described above.
I am thinking about disconnecting in case of SocketTimeoutException
There is no 'disconnection in case of SocketTimeoutException'.
and trying to connect the socket again.
You can't reconnect TCP sockets. You must close the current one and create a new one.
How feasible would that be?
Not in the slightest.
// not receiving -1 in case of socket close
See above re 'socket close'. If you're not receiving -1 from read() it is because there is no connection socket close.
When you receive a SocketTimeoutException, the socket is not closed, and neither is the connection, and there is no particular reason to close either of them. All it means is that no data arrived from the peer within the timeout you specified. Possibly the timeout is too short; possibly the peer is misbehaving. It is up to your application to decide which, based on the application protocol, expected service times, network latencies, ...
And 100ms is ridiculously short for a read timeout. It should be measured in seconds or tens of seconds.
This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 5 years ago.
When I'm using e.g. PuTTY and my connection gets lost (or when I do a manual ipconfig /release on Windows), it responds directly and notifies my connection was lost.
I want to create a Java program which monitors my Internet connection (to some reliable server), to log the date/times when my internet fails.
I tried use the Socket.isConnected() method but that will just forever return "true". How can I do this in Java?
Well, the best way to tell if your connection is interrupted is to try to read/write from the socket. If the operation fails, then you have lost your connection sometime.
So, all you need to do is to try reading at some interval, and if the read fails try reconnecting.
The important events for you will be when a read fails - you lost connection, and when a new socket is connected - you regained connection.
That way you can keep track of up time and down time.
Even though TCP/IP is "connection oriented" protocol, normally no data is sent over an idle connection. You can have a socket open for a year without a single bit sent over it by the IP stack. In order to notice that a connection is lost, you have to send some data on the application level.(*) You can try this out by unplugging the phone cable from your ADSL modem. All connections in your PC should stay up, unless the applications have some kind of application level keepalive mechanism.
So the only way to notice lost connection is to open TCP connection to some server and read some data from it. Maybe the most simple way could be to connect to some FTP server and fetch a small file - or directory listing - once in a while. I have never seen a generic server which was really meant to be used for this case, and owners of the FTP server may not like clients doing this.
(*) There is also a mechanism called TCP keepalive but in many OS's you have to activate it for all applications, and it is not really practical to use if you want to notice loss of connection quickly
If the client disconnects properly, a read() will return -1, readLine() returns null, readXXX() for any other X throws EOFException. The only reliable way to detect a lost TCP connection is to write to it. Eventually this will throw an IOException 'connection reset', but it takes at least two writes due to buffering.
Why not use the isReachable() method of the java.net.InetAddress class?
How this works is JVM implementation specific but:
A typical implementation will use ICMP ECHO REQUESTs if the privilege can be obtained, otherwise it will try to establish a TCP connection on port 7 (Echo) of the destination host.
If you want to keep a connection open continually so you can see when that fails you could connect to server running the ECHO protocol yourself rather than having isReachable() do it for you and read and write data and wait for it to fail.
You might want to try looking at the socket timeout interval. With a short timeout (I believe the default is 'infinite timeout') then you might be able to trap an exception or something when the host becomes unreachable.
Okay so I finally got it working with
try
{
Socket s = new Socket("stackoverflow.com",80);
DataOutputStream os = new DataOutputStream(s.getOutputStream());
DataInputStream is = new DataInputStream(s.getInputStream());
while (true)
{
os.writeBytes("GET /index.html HTTP/1.0\n\n");
is.available();
Thread.sleep(1000);
}
}
catch (IOException e)
{
System.out.println("connection probably lost");
e.printStackTrace();
}
Not as clean as I hoped but it's not working if I leave out the os.writeBytes().
You could ping a machine every number of seconds, and this would be pretty accurate. Be careful that you don't DOS it.
Another alternative would be run a small server on a remote machine and keep a connection to it.
Its probably simpler to connect to yahoo/google or somewhere like this.
URL yahoo = new URL("http://www.yahoo.com/");
URLConnection yc = yahoo.openConnection();
int dataLen = yc.getContentLength() ;
Neil
The isConnected()method inside Socket.java class is a little misleading. It does not tell you if the socket is currently connected to a remote host (like if it is unclosed). Instead, it tells you whether the socket has ever been connected to a remote host. If the socket was able to connect to the remote host at all, this method returns true, even after that socket has been closed. To tell if a socket is currently open, you need to check that isConnected() returns true and isClosed() returns false.
For example:
boolean connected = socket.isConnected() && !socket.isClosed();
I'm got the following Java code:
Socket s = new Socket();
s.connect(mySockAddr, myTimeout);
Assuming I don't use the socket, I need to detect a server side connection close (FIN or RST packet) as soon as it happens.
For instance, though a thread which checks socket status, or intercepting the FIN/RST packets...
How can I detect it?
I've tried with printWriter.checkError(), socket.isConnected(), socket.isClosed() methods but nothing works.
The only way i know of to detect whether the other side has closed the connection is by attempting to read from the input stream. A read from a shut-down socket will return -1. That's your notification that there won't be any more to read.
As far as the other functions go, s.isConnected() tells you whether you've successfully connect()ed the socket, and s.isClosed() would tell you whether you closed it. It tells you nothing about what the other side has done.
im trying to implement a client app with an asynchronous connection. i want to know if i can reuse a SocketChannel object after it has failed to connect to a server.
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
InetSocketAddress addr = new InetSocketAddress(host, port);
SelectionKey key = channel.register(select, SelectionKey.OP_READ, connection);
channel.connect(addr);
after this is the select loop, my socket eventually gets selected because the connection failed. i would like to queue another connection attempt on that channel, and nothing i do seems to do it. the channel.isConnectionPending() method always returns true (even if i try to finishConnect)
is the only solution do get rid of this SocketChannel and create a new one?
Sun has released the Java 6.0 sources under the GPL. "Read the source Luke"
And my reading of the code is that you cannot call connect a second time.
Hmmm... I'm no NIO expert but something looks fishy. You are registering for OP_ACCEPT, which occurs when a listening channel receives an incoming connection -- however, you're using the channel for an outgoing connection.
You should post more of the code, including the select loop.
Try it and see?
I'm not 100% sure, but I suspect you can once finishConnect has been called and returned or an exception from it thrown it may be ok.
Put a try/catch block around the connect and when the exception is caught you may be safe to call the channel.connect method again.
If it doesn't work then the answer is probably no.
This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 5 years ago.
When I'm using e.g. PuTTY and my connection gets lost (or when I do a manual ipconfig /release on Windows), it responds directly and notifies my connection was lost.
I want to create a Java program which monitors my Internet connection (to some reliable server), to log the date/times when my internet fails.
I tried use the Socket.isConnected() method but that will just forever return "true". How can I do this in Java?
Well, the best way to tell if your connection is interrupted is to try to read/write from the socket. If the operation fails, then you have lost your connection sometime.
So, all you need to do is to try reading at some interval, and if the read fails try reconnecting.
The important events for you will be when a read fails - you lost connection, and when a new socket is connected - you regained connection.
That way you can keep track of up time and down time.
Even though TCP/IP is "connection oriented" protocol, normally no data is sent over an idle connection. You can have a socket open for a year without a single bit sent over it by the IP stack. In order to notice that a connection is lost, you have to send some data on the application level.(*) You can try this out by unplugging the phone cable from your ADSL modem. All connections in your PC should stay up, unless the applications have some kind of application level keepalive mechanism.
So the only way to notice lost connection is to open TCP connection to some server and read some data from it. Maybe the most simple way could be to connect to some FTP server and fetch a small file - or directory listing - once in a while. I have never seen a generic server which was really meant to be used for this case, and owners of the FTP server may not like clients doing this.
(*) There is also a mechanism called TCP keepalive but in many OS's you have to activate it for all applications, and it is not really practical to use if you want to notice loss of connection quickly
If the client disconnects properly, a read() will return -1, readLine() returns null, readXXX() for any other X throws EOFException. The only reliable way to detect a lost TCP connection is to write to it. Eventually this will throw an IOException 'connection reset', but it takes at least two writes due to buffering.
Why not use the isReachable() method of the java.net.InetAddress class?
How this works is JVM implementation specific but:
A typical implementation will use ICMP ECHO REQUESTs if the privilege can be obtained, otherwise it will try to establish a TCP connection on port 7 (Echo) of the destination host.
If you want to keep a connection open continually so you can see when that fails you could connect to server running the ECHO protocol yourself rather than having isReachable() do it for you and read and write data and wait for it to fail.
You might want to try looking at the socket timeout interval. With a short timeout (I believe the default is 'infinite timeout') then you might be able to trap an exception or something when the host becomes unreachable.
Okay so I finally got it working with
try
{
Socket s = new Socket("stackoverflow.com",80);
DataOutputStream os = new DataOutputStream(s.getOutputStream());
DataInputStream is = new DataInputStream(s.getInputStream());
while (true)
{
os.writeBytes("GET /index.html HTTP/1.0\n\n");
is.available();
Thread.sleep(1000);
}
}
catch (IOException e)
{
System.out.println("connection probably lost");
e.printStackTrace();
}
Not as clean as I hoped but it's not working if I leave out the os.writeBytes().
You could ping a machine every number of seconds, and this would be pretty accurate. Be careful that you don't DOS it.
Another alternative would be run a small server on a remote machine and keep a connection to it.
Its probably simpler to connect to yahoo/google or somewhere like this.
URL yahoo = new URL("http://www.yahoo.com/");
URLConnection yc = yahoo.openConnection();
int dataLen = yc.getContentLength() ;
Neil
The isConnected()method inside Socket.java class is a little misleading. It does not tell you if the socket is currently connected to a remote host (like if it is unclosed). Instead, it tells you whether the socket has ever been connected to a remote host. If the socket was able to connect to the remote host at all, this method returns true, even after that socket has been closed. To tell if a socket is currently open, you need to check that isConnected() returns true and isClosed() returns false.
For example:
boolean connected = socket.isConnected() && !socket.isClosed();