如何关闭被I / O outputstream.write()阻止的Java SSLSocket?

时间:2018-08-14 09:23:07

标签: java multithreading tcp blocking sslsocketfactory

我读了这个问题 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套接字中做到这一点?

0 个答案:

没有答案