我们有下面的线程来执行 SSLHandshake 但在某些边缘情况下我注意到 ((SSLSocket) clientSocket).startHandshake();
被永远阻止并且它不会进入下一个 block while
循环代码,其中 SSL_HANDSHAKE_TIMEOUT 为 1500
毫秒并且工作正常,我想知道添加 clientSocket.setSoTimeout(90000);
是否会解决此问题或是否应该以不同的方式处理?
主服务器握手线程
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);
}
}
}
最佳答案
总结评论(主要来自@user207421):是的,通过 socket.setSoTimeout(timeout)
设置套接字超时如果握手过程在“一段时间”后仍未完成(但不一定 指定的超时时间1)。
这很简单,因为 setSoTimeout()
在套接字级别工作,在 SSL 握手之下:由 startHandshake()
执行的握手协议(protocol)涉及来自套接字Input
/OutputStream
的多次读/写,这将触发超时本身。换句话说:它本身不是“握手超时”,而是握手本身执行的所有读取操作的“读取超时”。
另外请注意,您不需要自己调用 startHandshake()
:当您第一次尝试从 SSLSocket
读取或写入时,JVM 会自动执行此操作(无论如何,在从 SSLServerSocket
获得这样的套接字之后,您通常会尽早执行此操作)。
1:setSoTimeout(timeout)
指定的超时是针对单个 read()
.因此,握手过程可能会在它执行的 read()
次数乘以您指定的 timeout
值后超时(在最坏的情况下)。
关于Java 8 : How to perform timeout for SSLSocket. 开始握手(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58307103/