我正在尝试将我的 Android (4.2) HTTP 客户端连接到 Jetty (9.1.3),使用 TLS 1.2 并交换受信任的证书 - 服务器在客户端受信任,客户端在服务器端受信任。我正在接收握手,客户端读取数据,但最多需要 6 秒。一些类来自 Apache HttpClient for Android 4.3.5 (GA)。
读取 keystore (在扩展应用程序的程序类中):
private javax.net.ssl.SSLContext sslContext;
private org.apache.http.client.CredentialsProvider credentialsProvider;
public void createSSLContext(String pin) {
InputStream store = null;
try {
String password = getPassword();
store = getResources().openRawResource(R.raw.key_store);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(store, password.toCharArray());
KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
keyFactory.init(keyStore, password.toCharArray());
trustFactory.init(keyStore);
String cn = null;
List<String> aliases = Collections.list(keyStore.aliases());
for (String alias : aliases) {
if (!alias.equalsIgnoreCase("server")) {
cn = alias;
break;
}
}
sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(keyFactory.getKeyManagers(), trustFactory.getTrustManagers(), null);
credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(String.format("%s:%s", cn, pin)));
} catch (Throwable t) {
Log.e(Program.TAG, t.getMessage(), t);
throw new RuntimeException(t.getMessage(), t);
} finally {
if (store != null) {
try {
store.close();
} catch (IOException e) {
Log.e(Program.TAG, e.getMessage(), e);
}
}
}
}
public SSLContext getSSLContext() {
return sslContext;
}
public HttpContext getHttpContext() {
HttpClientContext httpContext = HttpClientContext.create();
httpContext.setCredentialsProvider(credentialsProvider);
return httpContext;
}
还有一个客户端类:
public final class Client {
private Context context;
public Client(Context context) {
this.context = context;
}
public void execute() {
Program program = (Program) context.getApplicationContext();
CloseableHttpClient client =
HttpClients.custom()
.setSSLSocketFactory(
new SSLConnectionSocketFactory(program.getSSLContext(), new AllowAllHostnameVerifier()))
.build();
HttpContext httpContext = program.getHttpContext();
CloseableHttpResponse response = null;
HttpEntity entity = null;
try {
HttpGet get = new HttpGet("https://10.1.5.195:8088/application/Application");
response = client.execute(get, httpContext);
entity = response.getEntity();
String r = EntityUtils.toString(entity);
System.out.println(r);
} catch (Throwable t) {
Log.e(Program.TAG, t.getMessage(), t);
} finally {
if (response != null) {
try {
response.close();
} catch (IOException e) {
Log.e(Program.TAG, e.getMessage(), e);
}
}
if (entity != null) {
try {
entity.consumeContent();
} catch (IOException e) {
Log.e(Program.TAG, e.getMessage(), e);
}
}
try {
client.close();
} catch (IOException e) {
Log.e(Program.TAG, e.getMessage(), e);
}
}
}
}
Android 应用程序在移动设备(Samsung Galaxy S3、Cyanogenmod 11)上运行。移动设备和服务器都在同一个网络中(使用 wi-fi)。
在 AVD 上测试时一切正常。
我应该怎么做才能让它更快?我尝试设置 http 版本 1.1 参数,立即启用 tcp,但它没有改变任何东西。
在 Java SE 客户端中使用几乎相同的类时,接收数据大约需要 400 毫秒。
最佳答案
如果其他人遇到类似问题,请阅读一些 Jetty 文档:
SslContextFactory.html#newSSLEngine
If getNeedClientAuth() is true, then the host name is passed to newSSLEngine(String, int), possibly incurring in a reverse DNS lookup, which takes time and may hang the selector (since this method is usually called by the selector thread).
所以解决方案是在服务器端使用SslContextFactory.html#setWantClientAuth而不是 SslContextFactory.html#setNeedClientAuth .
关于Android 4.2 慢速 SSL/TLS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27228623/