I have a Java server that needs an option to shut down all connections. As part of this, I'm calling close() on each client socket. The problem I'm having is that this call sometimes blocks indefinitely.
I can only reproduce this by simulating several hundred users, so its hard to pinpoint, but I suspect that this happens when that socket is blocked on a write.
I read in another question that calling shutdownOutput() on the socket helps, but it is not supported by SSLSocket (which I am using).
Is there a another way? Whether or not any data queued up for write gets sent is not important - I just need to kill the connection.
After extensive testing of my own application I might be able to shed some light on this. The phenomenon I was observing was the following:
When closing a Java
SSLSocket
, which was opened and is handled inThread
A, from a concurrentThread
B, theclose()
call sometimes blocks until the nextread()
inThread
A, which then retruns indicatingEOF
. Between the asynchronous call toclose()
inThread
B and anyread()
inThread
A, A can successfully performwrite()
operations on that socket.I have now figured that this is only the case if
Thread
B performs theclose()
before thestartHandshake()
call initiated byThread
A has finished. After that, there seems to be no problem with closing theSSLSocket
asynchronously.This leaves us with the question how to solve the issue. Obviously, a bit of a state-based behaviour would help.
If one can live with a delay for the asynchronous
close()
inThread
B, callinggetSession()
beforeclose()
seems to work very well, because it makes B wait until A has the SSL session ready. However, this may cause a delay per socket, and also may lead to additional effort in case theclose()
does not get executed inThread
B before A starts to use the socket.A better, yet less simplistic solution would be to work with two uni-directional flags. One (
handshakeDone
) would be used by A to indicate that the SSL handshake has been completed (there's no non-blocking API way for B to find this out). The other (toBeClosed
) would be used by B to indicate that the socket is supposed to be closed.A would check
toBeClosed
after the handshake has been performed. B would callclose()
ifhandshakeDone
is false or settoBeClosed
otherwise.Note that for this to succeed, there need to be atomic blocks both in A and B. I'll leave the specific implementation (possibly optimized as compared to the algorithm described above) up to you.
There may be other situations where asynchronous
close()
calls on SSL sockets misbehave, though.