正确关闭SSLSocket

时间:2011-06-21 12:10:46

标签: java sockets ssl

我想在Java中实现SSL代理。我基本上打开了两个套接字browser-proxyproxy-server,并运行两个线程,这些线程将写入proxy-serverbrowser-proxy读取的内容,反之亦然。每个线程都是这样的:

while (true) {
   nr = in.read(buffer);
   if (nr == -1) System.out.println(sockin.toString()+" EOF  "+nr);
   if (nr == -1) break;
   out.write(buffer, 0, nr);
}
sockin.shutdownInput();
sockout.shutdownOutput(); // now the second thread will receive -1 on read

每个线程只关闭输入套接字,以便最终关闭两个套接字。

但如果我想使用SSLSocket该怎么办?似乎那里不支持shutdownOutput/Input方法。这是我得到的例外。

Exception in thread "Thread-35" java.lang.UnsupportedOperationException: \
The method shutdownInput() is not supported in SSLSocket
    at com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.shutdownInput(Unknown Source)

我想出的是:

try {
    while (true) {
       nr = in.read(buffer);
       if (nr == -1) System.out.println(sockin.toString()+" EOF  "+nr);
       if (nr == -1) break;
       out.write(buffer, 0, nr);
    }
    // possible race condition if by some mysterious way both threads would get EOF
    if (!sockin.isClosed()) sockin.close();
    if (!sockout.isClosed()) sockout.close();
} catch (SocketException e) {/*ignore expected "socket closed" exception, */}

每次套接字结束时,我必须捕获并忽略套接字异常结束。

我的问题是:

  1. 如果shutdownInput()不受支持,我将如何从-1获得SSLSocket答案。
  2. 我的痛苦有更好的解决方案吗?我认为没有任何理智,因为当另一个线程标记他“我已经完成”时,其中一个线程可能已经在阻塞read方法中。我看到将他踢出阻塞线程的唯一方法是关闭套接字并引发“关闭套接字”异常。

    (你可以猜测使用多线程消息传递和异步数据读取的一些邪恶组合,以便向你的工作完成其他线程发出信号,但这太可怕了,我害怕IntelliJ的风格警察会跟在我身后考虑一下......)

  3. 澄清:我知道shutdownInputshutdownOutput没有意义,因为根据规范,您无法使用半双工TLS连接。但鉴于此,如何在不结束异常的情况下结束Java中的TLS连接?

    请不要告诉我shutdownIput对TLS没有意义。我知道,这不是我要求的。我问我还能使用什么,以便正确关闭SSLSocket(因此标题为“正确关闭SSLSocket”。

3 个答案:

答案 0 :(得分:18)

答案 1 :(得分:0)

关闭连接的SSL语义与TCP不同,因此shutdownInput和shutdownOutput实际上没有意义,至少在SSLSocket中可用的控制级别。 SSLSocket基本上减轻了SSL记录处理和SSL握手消息处理的负担。它还处理SSL警报处理,其中一个警报是close_notify警报。以下是RFC 2246中有关此警报含义的文字。

"...Either party may initiate a close by sending a close_notify alert.
   Any data received after a closure alert is ignored.

   Each party is required to send a close_notify alert before closing
   the write side of the connection. It is required that the other party
   respond with a close_notify alert of its own and close down the
   connection immediately, discarding any pending writes. It is not
   required for the initiator of the close to wait for the responding
   close_notify alert before closing the read side of the connection...."

Java确实为自杀者提供了另一种API,即SSLEngine API。不要碰它,它会伤害你。

答案 2 :(得分:-3)

为了解决您的问题,您必须执行以下操作:

OutputStream sockOutOStream = sockout.getOutputStream();
sockOutOStream.write(new byte[0]);
sockOutOStream.flush();
sockout.close();

另一方面,从套接字读取的一方将收到-1-length消息,而不是抛出SocketException。