简体   繁体   English

为什么Java中的SSL Server套接字连接会阻塞而非SSL Server套接字却不会?

[英]Why does an SSL Server Socket connection block in Java whereas a non SSL Server Socket does not?

Consider the following code for a non-SSL Socket server and client all on the one thread: 对于一个线程上的非SSL套接字服务器和客户端,请考虑以下代码:

import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerClient {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(0); // open a random free port.

        Socket c = new Socket(ss.getInetAddress(), ss.getLocalPort());

        Socket s = ss.accept();

        final byte[] bytes = "Hello World!".getBytes();
        final OutputStream out = c.getOutputStream();
        System.out.println("writing to stream");
        out.write(bytes.length);
        out.write(bytes);

        System.out.println("reading from stream");

        final DataInputStream in = new DataInputStream(s.getInputStream());
        int len = in.read();
        final byte[] b = new byte[len];
        in.readFully(b);
        System.out.println(new String(b));

        c.close();
        ss.close();
    }
}

This produces the following output: 这将产生以下输出:

writing to stream
reading from stream
Hello World!

This process opened a server socket - connected with a client socket. 此过程打开了服务器套接字-与客户端套接字连接。 Passed data down the socket and then closed down. 通过套接字传递数据,然后关闭。 There was no issue passing the data. 传递数据没有问题。

Consider a version to a prove a point with SSL Sockets: 考虑使用SSL套接字来证明这一点的版本:

import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.logging.Logger;

public class SSLServerClient {

    private static Logger log = Logger.getLogger("InfoLogging");

    public static void main(String[] args) throws IOException {

        System.setProperty("javax.net.ssl.keyStore", "/path/KeyStore.jks");
        System.setProperty("javax.net.ssl.keyStorePassword", "password");

        SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();

        SSLServerSocket serverListeningSSLSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(4380);
        log.info("Server started");

        SSLSocketFactory sslSocketFactory=(SSLSocketFactory) SSLSocketFactory.getDefault();
        SSLSocket clientSocket =  (SSLSocket) sslSocketFactory.createSocket(serverListeningSSLSocket.getInetAddress(),
                serverListeningSSLSocket.getLocalPort());

        SSLSocket serverCommsSSLSocket = (SSLSocket) serverListeningSSLSocket.accept();
        log.info("new client");

        final byte[] bytes = "Hello World!".getBytes();
        final OutputStream out = clientSocket.getOutputStream();
        System.out.println("writing to stream");
        out.write(bytes.length);
        out.write(bytes);

        System.out.println("reading from stream");

        final DataInputStream in = new DataInputStream(serverCommsSSLSocket.getInputStream());
        int len = in.read();
        final byte[] b = new byte[len];
        in.readFully(b);
        System.out.println(new String(b));

        clientSocket.close();
        serverCommsSSLSocket.close();
        serverListeningSSLSocket.close();
    }
}

This gives the following output: 这给出以下输出:

Nov 21, 2018 10:23:51 PM com.gamble.ssl.SSLServerClient main INFO: Server started
Nov 21, 2018 10:23:52 PM com.gamble.ssl.SSLServerClient main INFO: new client
writing to stream

ie it blocks on the server socket starting. 即它阻止了服务器套接字启动。

My question is: Why does an SSL Server Socket connection block in Java whereas a non SSL Server Socket does not? 我的问题是: 为什么Java中的SSL Server套接字连接会阻塞而非SSL Server套接字却不会?

What does "flip to plaintext?" 什么是“跳至明文”? mean? 意思?

Here's what you are doing: 这是你在做什么:

  • Creating an SSL server socket 创建一个SSL服务器套接字
  • Creating a normal socket connected to the SSL server socket 创建连接到SSL服务器套接字的普通套接字
  • Sending some data from the client side 从客户端发送一些数据
  • Reading some data on the server side 在服务器端读取一些数据

Now, the SSL socket expects encrypted data transfer. 现在,SSL套接字需要加密的数据传输。 But the data you are not sending is not encrypted, so it's not valid SSL and it throws an exception - as it says, "Unrecognized SSL message" because you are not sending a valid SSL message, and "plaintext connection?" 但是,您未发送的数据未加密,因此它不是有效的SSL,并且会引发异常-如“未识别的SSL消息”之类,因为您未发送有效的SSL消息,并且为“纯文本连接?”。 is a hint about what might be wrong. 暗示什么可能是错的。

You have to use SSL on both sides of the connection, or they can't talk to each other properly. 您必须在连接的两边都使用SSL,否则它们将无法正确通信。

The simple answer to the question is: 这个问题的简单答案是:

Because an SSL Handshake is asynchronous and the non SSL socket doesn't have to do that step. 由于SSL握手是异步的非SSL套接字不必执行此步骤。

Ok - there were two issues with the original SSL Code: 好的-原始SSL代码有两个问题:

  1. There was no TrustStore: 没有TrustStore:

     System.setProperty( "javax.net.ssl.trustStore", "/path/KeyStore.jks"); 
  2. Because the Handshake is synchronous - you have to start the client on a different thread. 因为握手是同步的,所以您必须在其他线程上启动客户端。 ie: 即:

     (new Thread() { public void run() { // do stuff } }).start(); 

So the code looks like: 因此,代码如下所示:

    import javax.net.ssl.SSLServerSocket;
    import javax.net.ssl.SSLServerSocketFactory;
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.SSLSocketFactory;
    import java.io.DataInputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.logging.Logger;

    public class SSLServerClient {

        public static void main(String[] args) throws IOException {

            System.setProperty("javax.net.ssl.keyStore", "/path/KeyStore.jks");
            System.setProperty( "javax.net.ssl.trustStore", "/path/KeyStore.jks");

            System.setProperty("javax.net.ssl.keyStorePassword", "password");

            SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();

            SSLServerSocket serverListeningSSLSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(4380);
            System.out.println("--server started");

            SSLSocketFactory sslSocketFactory=(SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket clientSocket =  (SSLSocket) sslSocketFactory.createSocket(serverListeningSSLSocket.getInetAddress(),
                    serverListeningSSLSocket.getLocalPort());

            SSLSocket serverCommsSSLSocket = (SSLSocket) serverListeningSSLSocket.accept();
            System.out.println("--new client");

            final byte[] bytes = "--Hello World!".getBytes();
            final OutputStream out = clientSocket.getOutputStream();
            System.out.println("--Gotten output stream");
            final DataInputStream in = new DataInputStream(serverCommsSSLSocket.getInputStream());

            (new Thread() {
                public void run() {
                    System.out.println("--reading from stream");

                    int len = 0;
                    try {
                        len = in.read();
                        final byte[] b = new byte[len];
                        in.readFully(b);
                        System.out.println(new String(b));

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();


            System.out.println("--writing to stream");
            out.write(bytes.length);
            System.out.println("--writing to stream - length");
            out.write(bytes);

            clientSocket.close();
            serverCommsSSLSocket.close();
            serverListeningSSLSocket.close();
        }
    }

And the output looks like 输出看起来像

    --server started
    --new client
    --Gotten output stream
    --writing to stream
    --reading from stream
    --writing to stream - length
    --Hello World!

    Process finished with exit code 0

Done 完成

(Note I added the leading -- to the output to aid when reading SSL Debug output. (请注意,我在输出中添加了前导--以便在读取SSL调试输出时提供帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM