多线程Java 8:如何为SSLSocket执行超时。startHandshake()
我们有下面的线程来执行SSLHandshake,但在一些边缘情况下,我注意到((SSLSocket) clientSocket).startHandshake();
被永久阻止,它不会进入下一个while
循环代码块,其中SSL_握手_超时为1500
毫秒,它工作正常,我想知道添加clientSocket.setSoTimeout(90000);
是否会解决这个问题,或者应该以不同的方式处理
Main服务器握手阅读
public class MainServerHandshakeThread implements com.ssltunnel.utilities.threading.Shutdown, Runnable {
private final Socket clientSocket;
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(MainServerHandshakeThread.class.getName());
private boolean done;
public MainServerHandshakeThread(Socket clientSocket) {
this.clientSocket = clientSocket;
}
private void handshake() throws CertificateExpiredException, InterruptedException, IOException {
long start = System.currentTimeMillis();
((SSLSocket) clientSocket).setNeedClientAuth(true);
MainServerHandshakeHandler handshake = new MainServerHandshakeHandler();
((SSLSocket) clientSocket).addHandshakeCompletedListener(handshake);
((SSLSocket) clientSocket).startHandshake();
while (!handshake.isDone() && !done) {
Thread.sleep(10);
long duration = System.currentTimeMillis() - start;
if (duration>SSL_HANDSHAKE_TIMEOUT) {
done = true;
LOG.warn("Handshake timeout");
}
}
long stop = System.currentTimeMillis();
serialNumber = handshake.getSerialNumber();
LOG.info("MainServer Handshake Handshake done in ms: " + ((stop - start))+" For serialNumber "+serialNumber );
}
@Override
public void run() {
try {
handshake();
} catch (CertificateExpiredException ex) {
LOG.error("Client Certificate Expired", ex.getMessage());
SocketUtils.closeQuietly(clientSocket);
}
catch (InterruptedException ex) {
LOG.error("Interrupted waiting for handshake", ex);
SocketUtils.closeQuietly(clientSocket);
}
catch (IOException ex) {
LOG.error("IO Error waiting for handshake", ex);
SocketUtils.closeQuietly(clientSocket);
}
finally {
LOG.debug("Handshake thread is done");
done = true;
}
}
@Override
public void shutdown() {
if (clientSocket!=null) {
SocketUtils.closeQuietly(clientSocket);
}
}
}
# 1 楼答案
总结一下评论(主要来自@user207421):是的,如果握手过程在“一段时间”后没有完成(但是不一定指定的超时1),那么通过^{} 设置套接字超时将足以触发
SocketTimeoutException
(一个IOException
的子类)这一点很简单,因为} 执行的握手协议涉及来自套接字
setSoTimeout()
在套接字级别上工作,低于SSL握手:由^{Input
/OutputStream
的几次读/写,这将触发超时本身。换句话说:它本身不是“握手超时”,而是握手本身执行的所有读取操作的“读取超时”另外,请注意,您不需要自己调用
startHandshake()
:当您第一次尝试从SSLSocket
读取或写入数据时,JVM将自动执行此操作(不管怎样,在您从SSLServerSocket
获得这样的套接字之后,您通常会提前执行此操作)1:由} 。因此,握手过程可以在执行的
setSoTimeout(timeout)
指定的超时用于单个^{read()
数乘以指定的timeout
值之后超时(在最坏的情况下)# 2 楼答案
SSLSocket的大多数实现都支持setHandshakeTimeout(),但它不是类定义的一部分。 我建议你看看Android代码的例子。这是如何应对的一个很好的例子: ssl socket factory wrapper和ssl socket factory
检查他们如何尝试设置握手超时(如果存在):
看看他们是如何建立联系的:
希望有帮助