如何关闭阻塞的SSLSocket?

时间:2013-01-09 09:51:35

标签: java jsse

我有一台Java服务器需要一个关闭所有连接的选项。作为其中的一部分,我在每个客户端套接字上调用close()。我遇到的问题是这个电话有时会无限期地阻塞。

我只能通过模拟几百个用户来重现这一点,所以很难确定,但我怀疑在写入时阻塞该套接字时会发生这种情况。

我在另一个问题中读到,在套接字上调用shutdownOutput()会有所帮助,但SSLSocket(我正在使用它)不支持它。

还有另一种方式吗?

是否需要终止任何排队等待写入的数据并不重要 - 我只需要终止连接。

1 个答案:

答案 0 :(得分:4)

经过对我自己的应用程序的大量测试后,我可能会对此有所了解。我观察到的现象如下:

关闭已打开并在SSLSocket A 中处理的 Java Thread来自并发Thread < em> B ,close()调用有时会阻塞read() A 中的下一个Thread,然后重新显示EOF。在close() B 中的Threadread() A 中的任何Thread的异步调用之间, A 可以在该套接字上成功执行write()次操作。

我现在认为只有Thread B close() <{1}}发起的startHandshake()来电之前执行Thread时才会出现这种情况。 em> A 已经完成。之后,异步关闭SSLSocket似乎没有问题。

这给我们留下了如何解决问题的问题。显然,一些基于状态的行为会有所帮助。

如果close() B 中的异步Thread有延迟,那么在getSession()之前调用close()似乎效果很好,因为它使 B 等到 A 准备好SSL会话。但是,这可能会导致每个插槽出现延迟,并且如果在 A之前close() B Thread未执行,则可能会导致额外的工作开始使用套接字。

更好但不那么简单的解决方案是使用两个单向标志。 A 将使用一个(handshakeDone)来表示SSL握手已完成( B 没有非阻塞API方式找到这个)。 B 将使用另一个(toBeClosed)来指示套接字应该关闭。

A 将在执行握手后检查toBeClosed。如果close()为false,则 B 会调用handshakeDone,否则会设置为toBeClosed

请注意,要成功完成此操作, A B 中都需要有原子块。我将保留具体实现(可能与上述算法相比优化)。

但是,可能还有其他情况下,对SSL套接字的异步close()调用行为不正常。