我有一台Java服务器需要一个关闭所有连接的选项。作为其中的一部分,我在每个客户端套接字上调用close()。我遇到的问题是这个电话有时会无限期地阻塞。
我只能通过模拟几百个用户来重现这一点,所以很难确定,但我怀疑在写入时阻塞该套接字时会发生这种情况。
我在另一个问题中读到,在套接字上调用shutdownOutput()会有所帮助,但SSLSocket(我正在使用它)不支持它。
还有另一种方式吗?
是否需要终止任何排队等待写入的数据并不重要 - 我只需要终止连接。答案 0 :(得分:4)
经过对我自己的应用程序的大量测试后,我可能会对此有所了解。我观察到的现象如下:
关闭已打开并在SSLSocket
A 中处理的 Java Thread
来自并发Thread
< em> B ,close()
调用有时会阻塞read()
A 中的下一个Thread
,然后重新显示EOF
。在close()
B 中的Thread
与read()
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()
调用行为不正常。