我们有下面的线程可以执行SSLHandshake,但是在某些情况下,我注意到((SSLSocket) clientSocket).startHandshake();
被永久阻止,并且不会转到下一个while
循环代码块,其中SSL_HANDSHAKE_TIMEOUT是1500
毫秒,并且可以正常工作,我想知道是否添加clientSocket.setSoTimeout(90000);
是否可以解决此问题还是应该以其他方式处理?
MainServerHandshakeThread
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)
设置套接字超时就足以触发SocketTimeoutException
(IOException
的子类)。指定的超时时间1)。
可以简单地解释一下原因,因为setSoTimeout()
在SSL握手之下的套接字级别工作: startHandshake()
执行的握手协议(protocol)涉及对套接字Input
/OutputStream
的多次读取/写入,这将触发超时本身。换句话说:它本身不是“握手超时”,而是握手本身执行的所有读取操作的“读取超时”。
另外,请注意,您无需自己调用startHandshake()
:当您首次尝试从SSLSocket
读取或写入时,JVM会自动执行此操作(通常无论如何从SSLServerSocket
获得这样的套接字后,通常都会这样做)。
1:setSoTimeout(timeout)
指定的超时是针对单个 read()
的。因此,握手过程可能会在执行的read()
数乘以您指定的timeout
值后超时(在最坏的情况下)。