我读了这个问题 How to close a blocked SSLSocket?
但是不太了解解决方案。所以我再次用示例代码问这个问题。
线程A。
public static void sendData(final SSLSocket sslSocket){
sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites());
sslSocket.startHandshake();
socket = (Socket) sslSocket;
socket.setSoTimeout(1200);
socket.setTcpNoDelay(true);
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
while(true){
outputStream.write("abc".getBytes());
}
}
从客户端接收到连接后,线程A开始向该客户端连续发送数据。
线程B:
if(socket != null && !socket.isClosed()) {
socket.close();
}
System.out.println("socket has been closed");
if(outputStream!=null)
outputStream.close();
if(inputStream!=null)
inputStream.close();
假设1分钟后线程B醒来并试图关闭套接字。
问题:
while(true){
outputStream.write("abc".getBytes());
}
由于线程A连续写入客户端而没有任何睡眠。不久之后,服务器的输出缓冲区将已满,并且
outputStream.write("abc".getBytes());
此行进入阻止状态。如果服务器写得太快,那么很快它将处于阻塞状态。
如果服务器当时处于阻塞状态,则线程B唤醒并尝试关闭套接字。然后它也进入阻塞状态。
inputStream.close();
outputStream.close();
socket.close();
如果线程B尝试调用这三行中的任何一条,那么线程B也会进入阻塞状态。
如果我使用jstack,那么我可以看到线程B正在等待获取锁。
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000004d26374f0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:845)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:717)
at sun.security.ssl.SSLSocketImpl.sendAlert(SSLSocketImpl.java:2069)
at sun.security.ssl.SSLSocketImpl.warning(SSLSocketImpl.java:1896)
at sun.security.ssl.SSLSocketImpl.closeInternal(SSLSocketImpl.java:1664)
- locked <0x00000004d2636e80> (a sun.security.ssl.SSLSocketImpl)
at sun.security.ssl.SSLSocketImpl.close(SSLSocketImpl.java:1602)
at sun.security.ssl.AppInputStream.close(AppInputStream.java:150)
如果这是一个简单的TCP套接字(不是SSLSocket),则线程B可能已经关闭了该套接字,而不管线程A在读取或写入时是否处于阻塞状态。
如何在SSL套接字中做到这一点?