What can go wrong if I simply replace
socket = new Socket()
with
socket = SocketChannel.open().socket()?
Background: I have some legacy code using new Socket(), and I wanted to be able to interrupt the socket.connect() call. I don't want to rewrite the code to use NIO. I learned that Thread.interrupt() does not interrupt socket.connect(), but that socket.close() on another thread is supposed to interrupt the connection. Oddly, that worked with Java 7 but not Java 6.
I somehow got it into my head that using socket = SocketChannel().open().socket() would magically allow me to use Thread.interrupt() to interrupt socket.connect(). It doesn't, but oddly, it does make socket.close() interrupt socket.connect() in Java 6 too!
Note that I'm not directly using the attached SocketChannel in any way---it appears when I create the Socket and never again.
What can go wrong with this?
There are several.
A Socket acquired via a SocketChannel doesn't appear to support read timeouts.
The InputStream and OutputStream of a socket aren't independent: they have a mutual lock in common.
Why do you want to interrupt the connect() call? Surely all you want is a connect timeout?
Differences in the type of thrown exceptions could break existing code.
For instance, closing a Socket from a different thread while Socket.getInputStream().read() is blocking will result in AsynchronousCloseException after replacing, instead of SocketException that legacy code could be expecting. (AsynchronousCloseException is not a subclass of SocketException.)
However, Socket.getInputStream().read() will still throw SocketException if the close from the other thread gets in before read().
Related
This is a pretty basic question, but I can't find a definitive answer for it anywhere:
When I accept() a connection from a ServerSocketChannel, am I guaranteed that the returned SocketChannel is "connected", or could it happen that the returned channel is still performing some form a handshake or whatever and will only later set its SelectionKey.OP_CONNECT bit?
In other words, am I guaranteed that the following piece of code will never print false?
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(1234));
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println(socketChannel.isConnected());
According to the source of ServerSocketChannelImpl the ServerSocketChannelImpl creates a SocketChannelImpl with a state of ST_CONNECTED.
Since the SocketChannelImpl.isConnected() method checks for a state of ST_CONNECTED, your test should always return true.
That is however the scenario for the good times. What could happen is that your server thread gets delayed and by the time your thread calls isConnected() the client already closed the connection.
So, no, there is no guarantee that your code will never print false.
The state of SocketChannel and the underlying socket are independent until synchronized through a read/write operation. There is no guarantee that the socket is still open after calling accept().
So basically, SocketChannel.isConnected() is ALWAYS going to return TRUE after calling accept() but that is essentially a guess. It doesn't really know! The only way to test this is to try to read/write some data to the SocketChannel.
Writing data to the channel will reveal if the socket is still open on the remote computer. You can test this behavior by connecting client and server using a switch then removing a networking cable of one of the computers. You will see how the sockets will stay open for a very long time. There are some socket options that can be used to mitigate this but not by much.
Reading from the SocketChannel will only reveal that it is closed if read() returns -1;
I have a thread for each connection on the server-side. When the client is not sending commands, the server thread is blocking:
while ((commandHeader = fromNode.readLine()) != null) {
which internally calls readLine() on an OutputStream obtained from the TCP socket.
When I call socket.close() from another thread, this calls wakes up with a SocketException and the thread can be terminated.
However, if a client than wakes up and decide to issue a command, it executes
stream.writeBytes("something\n");
which blocks indefinitely. I understand this is probably fine for TCP (it's just an half-close.)
I should probably send something to the client upon quitting, like "QUIT\n"; it could also just read an EOF. But if I call readLine() or other read operations on the client before sending the command, they block waiting for data when the connection is not closed.
How can the client detect that the connection has been half-closed before trying to write to it?
When socket.close() is called on server the underlying TCP connection is closed with the typical FIN/FIN-ACK sequence plus RST packets, so the client will know. When the client calls stream.writeBytes() afterwards it should fail. If it doesn't it means there has been some missing packets and the connection eventually will fail anyhow.
First i think your application logic should be such that to avoid Half Open TCP connection. You can think of adding timer on client side so that if nothing received it starts polling the server again.
From server point of view, another option is to set timer on the readLine. Make another method for readLine where you set a timer and if it excedes certain time, simply return some default value to the while loop.
EDIT:
You might want to read this article specially the section: What about threads blocked on IO?
In the context of Java, I create a new thread to read network input when open a GUI window, and when i close the window, i want to release the socket resource and terminate the thread immediately. Now i am using setSoTimeout method, but i don't want to wait the timeout exception. Could anybody give some suggestion? Thanks!
There are (potentially) three ways to do this:
Calling Socket.close() on the socket will close the associated InputStream and OutputStream objects, and cause any threads blocked in Socket or (associated) stream operations to be unblocked. According to the javadoc, operations on the socket itself will throw a SocketException.
Calling Thread.interrupt() will (under some circumstances that are not specified) interrupt a blocking I/O operation, causing it to throw an InterruptedIOException.
Note the caveat. Apparently the "interrupt()" approach doesn't work on "most" modern Java platforms. (If someone else had the time and inclination, they could possible investigate the circumstances in which this approach works. However, the mere fact that the behavior is platform specific should be sufficient to say that you should only use it if you only need your application to work on a specific platform. At which point you can easily "try it" for yourself.)
A possible third way to do this is to call Socket.shutdownInput() and/or Socket.shutdownOutput(). The javadocs don't say explicitly what happens with read and/or write operations that are currently blocked, but it is not unreasonable to think that they will unblock and throw an exception. However, when the javadoc doesn't say what happens, the behavior should be assumed to be platform specific.
I know this question is old but as nobody seems to have solved the "mystery" of Thread.interrupt() on "modern platforms" I did some research.
This is tested on Java 8 on Windows7 (64-bit) (but it will possibly be true for other platforms as well).
Calling Thread.interrupt() does not throw an InterruptedIOException
What happens is that the InputStream.read() method returns with -1 and Thread.interrupted()-flag is set.
So the following could be considered a 'corrected' read() throwing InterruptedIOException:
static final int read(Socket socket, byte[] inData)
throws SocketTimeoutException, // if setSoTimeout() was set and read timed out
InterruptedIOException, // if thread interrupted
IOException // other erors
{
InputStream in = socket.getInputStream();
int readBytes = in.read( inData, 0, inData.length);
if ( Thread.interrupted() )
{
throw new InterruptedIOException( "Thread interrupted during socket read");
}
return readBytes;
}
I use a Java Socket object in my client application. I need to know when the line to the server is broken, or if any event caused the socket to be dead.
I see two methods:
catching SocketException when writing in or reading from the socket, considering these exceptions kill the socket
when catching these exceptions, checking the Socket.isClosed() method to know if it killed the socket
Does any of these methods guarantee I'll know when the socket is dead and won't work again, even if a temporary problem on the line is solved?
Can we except a (Socket)Exception thrown during an operation on a socket to imply the socket is dead?
Is there a better method to know this?
At least:
Receiving an exception does NOT mean the socket is always dead, from Socket.setSoTimeout() javadoc:
If the timeout expires [on a read for instance, a java.net.SocketTimeoutException is raised, though the Socket is still valid.
The closed flag of the socket seems to be set only when the Socket.close() method is called, so I would not rely on it.
This is usually done by a timeout. This is mandatory if you don't trust the other side (like every time). Without a timeout, an attacker can DoS your application easily by opening connections without sending anything. Once you hit the socket limit of your system, the application might even crash...
A "Dead Socket" can be considered as an abnormal status. It is just a errornous bahaviour. So I don't think you can handle this situation effectively.
Since there is nothing like a keep-alive between sockets, you will learn that the connection is broken not until ,next time you try to write onto this socket.
This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 1 year ago.
Hey all. I have a server written in java using the ServerSocket and Socket classes.
I want to be able to detect and handle disconnects, and then reconnect a new client if necessary.
What is the proper procedure to detect client disconnections, close the socket, and then accept new clients?
Presumably, you're reading from the socket, perhaps using a wrapper over the input stream, such as a BufferedReader. In this case, you can detect the end-of-stream when the corresponding read operation returns -1 (for raw read() calls), or null (for readLine() calls).
Certain operations will cause a SocketException when performed on a closed socket, which you will also need to deal with appropriately.
The only safe way to detect the other end has gone is to send heartbeats periodically and have the other end to timeout based on a lack of a heartbeat.
Is it just me, or has nobody noticed that the JavaDoc states a method under ServerSocket api, which allows us to obtain a boolean based on the closed state of the serversocket?
you can just loop every few seconds to check the state of it:
if(!serverSocket.isClosed()){
// whatever you want to do if the serverSocket is connected
}else{
// treat a disconnected serverSocket
}
EDIT: Just reading your question again, it seems that you require the server to just continually search for connections and if the client disconnects, it should be able to re-detect when the client attempts to re-connect. should'nt that just be your solution in the first place?
Have a server that is listening, once it picks up a client connection, it should pass it to a worker thread object and launch it to operate asynchronously. Then the server can just loop back to listening for new connections. If the client disconnects, the launched thread should die and when it reconnects, a new thread is launched again to handle the new connection.
Jenkov provides a great example of this implementation.