使用SSLSocket的TLS连接在Android OS中很慢

Art*_*hur 10 java sockets ssl android

我正在开发一个使用SSLSocket连接到服务器的Android应用程序.这是我正在使用的代码:

// Connect
if (socket == null || socket.isClosed() || !socket.isConnected()) {
    if (socket != null && !socket.isClosed())
        socket.close();
    Log.i(getClass().toString(), "Connecting...");
    if (sslContext == null) {
        sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustAllCerts, new SecureRandom()); 
    }
    SSLSocketFactory socketFactory = sslContext.getSocketFactory();
    socket = (SSLSocket)socketFactory.createSocket(host, port);
    socket.setSoTimeout(20000);
    socket.setUseClientMode(true);
    connected = true;
    Log.i(getClass().toString(), "Connected.");
}

// Secure
if (connected) {
    Log.i(getClass().toString(), "Securing...");
    SSLSession session = socket.getSession();
    secured = session.isValid();
    if (secured) {
        Log.i(getClass().toString(), "Secured.");
    }
    else
        Log.i(getClass().toString(), "Securing failed.");
}
Run Code Online (Sandbox Code Playgroud)

问题是在下面的行中进行TLS握手需要大约5秒或更多事件:

SSLSession session = socket.getSession();
Run Code Online (Sandbox Code Playgroud)

我做了一个类似的iPhone应用程序,握手只需1秒钟,所以我认为问题不在我正在连接的服务器中,它可能在上面的代码中.连接本身足够快,只是TLS握手很慢.

有人知道它在Android中是否正常,或者如果不是,如何让它更快?

谢谢.

于21.01.11编辑:

我发现,当我连接到另一台服务器时握手很快,例如paypal.com:443.

但我以前连接过另一台服务器 - 我写的一个.NET服务.正如我之前所说,我不认为问题出现在那台服务器上,因为如果我用我的iPhone App连接它,握手很快.现在我不知道为什么它在iPhone上速度快,在Android上速度慢.建立连接后,我在.NET服务器中做的唯一事情是:

Console.WriteLine("New client connected.");
this.sslStream = new SslStream(tcpClient.GetStream(), true);
this.sslStream.ReadTimeout = 15000;
this.sslStream.WriteTimeout = 15000;

Console.WriteLine("Beginning TLS handshake...");
this.sslStream.AuthenticateAsServer(connection.ServerCertificate, false, SslProtocols.Tls, false);
Console.WriteLine("TLS handshake completed.");
Run Code Online (Sandbox Code Playgroud)

Yuy*_*uyo 6

早期版本的Android SDK存在一个错误.显然,它正在进行不必要的DNS反向查找.你需要防止这种情况发生.这是一个对我有用的解决方法.过去需要15秒,现在需要0-1秒.希望能帮助到你.

这是Google 问题的链接.

boolean connected = false;
if (socket == null || socket.isClosed() || !socket.isConnected()) {
    if (socket != null && !socket.isClosed()) {
        socket.close();
    }

    Log.i(getClass().toString(), "Connecting...");
    messages.getText().append("Connecting...");
    final KeyStore keyStore = KeyStore.getInstance("BKS");
    keyStore.load(getResources().openRawResource(R.raw.serverkey), null);

    final KeyManagerFactory keyManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    keyManager.init(keyStore, null);
    //keyManager.init(null, null);

    final TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustFactory.init(keyStore);

    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(keyManager.getKeyManagers(), trustFactory.getTrustManagers(), rnd);
    final SSLSocketFactory delegate = sslContext.getSocketFactory();
    SocketFactory factory = new SSLSocketFactory() {
        @Override
        public Socket createSocket(String host, int port)
                        throws IOException, UnknownHostException {

            InetAddress addr = InetAddress.getByName(host);
            injectHostname(addr, host);
            return delegate.createSocket(addr, port);
        }
        @Override
        public Socket createSocket(InetAddress host, int port)
                        throws IOException {

            return delegate.createSocket(host, port);
        }
        @Override
        public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
                        throws IOException, UnknownHostException {

            return delegate.createSocket(host, port, localHost, localPort);
        }
        @Override
        public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
                        throws IOException {

            return delegate.createSocket(address, port, localAddress, localPort);
        }
        private void injectHostname(InetAddress address, String host) {
            try {
                Field field = InetAddress.class.getDeclaredField("hostName");
                field.setAccessible(true);
                field.set(address, host);
            } catch (Exception ignored) {
            }
        }
        @Override
        public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {

            injectHostname(s.getInetAddress(), host);
            return delegate.createSocket(s, host, port, autoClose);
        }
        @Override
        public String[] getDefaultCipherSuites() {
            return delegate.getDefaultCipherSuites();
        }
        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        }
    };
    socket = (SSLSocket)factory.createSocket("192.168.197.133", 9999);
    socket.setSoTimeout(20000);
    socket.setUseClientMode(true);
    connected = true;
    Log.i(getClass().toString(), "Connected.");
    messages.getText().append("Connected.");
}

// Secure
if (connected) {
    Log.i(getClass().toString(), "Securing...");
    messages.getText().append("Securing...");
    SSLSession session = socket.getSession();
    boolean secured = session.isValid();
    if (secured) {
        Log.i(getClass().toString(), "Secured.");
        messages.getText().append("Secured.");
    }
}
Run Code Online (Sandbox Code Playgroud)


bli*_*uff 0

我已经做了类似的事情,它比不安全的连接慢。当然,我的情况是 https 与 http,但略有不同,SSL/TLS 因素会增加交易速度。

我有两个相同的应用程序,它们使用相同的协议与同一服务器进行通信,一个在 Android 中,一个在 iPhone 中,都使用 https。当我在 http 中测试它们时,我会看到或多或少相同的响应时间,在 https 中,iOS 在我的情况下稍微快一点,但不是特别快。