Android操作系统中使用SSLSocket的TLS连接速度较慢

我正在开发一个使用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."); } 

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

 SSLSession session = socket.getSession(); 

我做了一个类似的iPhone应用程序,握手只需要1秒钟,所以我认为这个问题不在我连接的服务器上,也许在上面的代码中。 连接本身速度够快,只是TLS握手很慢。

有谁知道在Android中是否正常,或者不知道如何使其更快?

谢谢。

编辑于21.01.11:

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

但是我之前已经连接到另一台服务器 – 我写的一个.NET服务。 正如我以前说过的,我不认为问题出在那个服务器上,因为如果我用iPhone App连接它,握手很快。 现在我不知道为什么它在iPhone上很快,在Android上很慢。 连接build立后,我在.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."); 

Related of "Android操作系统中使用SSLSocket的TLS连接速度较慢"

早期版本的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."); } } 

每个连接使用一个新的SecureRandom ,而不是使用一个静态预初始化的SecureRandom 。 每次你创build一个新的SecureRandom(),你需要收集熵播种(一个缓慢的过程)。

SecureRandom在第一次使用之前不会自我种子,这就是为什么在调用getSession()之前不会发生延迟的原因。

我做了类似的事情,比不安全的连接慢。 当然,我的情况是https和http,它有点不同,SSL / TLS因素会增加交易的缓慢。

我有两个相同的应用程序,使用相同的协议交互到相同的服务器,一个在Android和一个iPhone,都使用https。 当我在http中testing它们的时候,我会看到或多或less的相同的响应时间,在https iOS中我的情况稍微快一些,但不是很糟糕。

问题很可能以设备validation服务器证书的方式进行。 validation可能涉及与CRL和OCSP响应的第三方联系。 如果发生这种情况,则需要时间。 iPhone可能只是不这样做(至less默认情况下),这是一个安全漏洞BTW。