我有一个需要关闭所有连接的选项的 Java 服务器。作为其中的一部分,我在每个客户端套接字上调用 close()。我遇到的问题是这个调用有时会无限期地阻塞。
我只能通过模拟数百个用户来重现这一点,因此很难确定,但我怀疑当该套接字在写入时被阻塞时会发生这种情况。
我在另一个问题中读到,在套接字上调用 shutdownOutput() 会有所帮助,但 SSLSocket(我正在使用)不支持它。
还有其他方法吗?排队等待写入的任何数据是否被发送并不重要——我只需要终止连接。
在对我自己的应用程序进行广泛测试之后,我或许能够对此有所了解。我观察到的现象如下:
当从并发B关闭一个在 A中打开并在A中处理的Java 时,调用有时会阻塞,直到 A 中的下一个,然后返回指示。在对in B的异步调用和对A的任何调用之间,A可以成功地对该套接字执行操作。SSLSocket
Thread
Thread
close()
read()
Thread
EOF
close()
Thread
read()
Thread
write()
我现在认为,只有在A发起的呼叫完成之前Thread
B执行了才会出现这种情况。之后,异步关闭似乎没有问题。close()
startHandshake()
Thread
SSLSocket
这给我们留下了如何解决问题的问题。显然,一些基于状态的行为会有所帮助。
如果可以忍受Bclose()
中的异步延迟,那么之前调用似乎工作得很好,因为它使B等到A准备好 SSL 会话。但是,这可能会导致每个套接字的延迟,并且如果在A开始使用套接字之前没有在B中执行,也可能会导致额外的工作量。Thread
getSession()
close()
close()
Thread
一个更好但不那么简单的解决方案是使用两个单向标志。AhandshakeDone
将使用一个 ( ) 来指示 SSL 握手已完成( B没有非阻塞 API 方法可以找出这一点)。B将使用另一个 ( )来指示套接字应该关闭。toBeClosed
A将toBeClosed
在握手完成后进行检查。B将调用close()
ifhandshakeDone
为 false 或toBeClosed
以其他方式设置。
请注意,要成功, A和B中都需要有原子块。我将把具体的实现(与上述算法相比可能进行了优化)留给你。
但是,在其他情况下,close()
对 SSL 套接字的异步调用可能会出现异常。