1

複数のクライアント(クライアント証明書を持つクライアント)で使用されているアプリケーションがあります。このアプリケーションは、HTTPSを介して(HttpClientを使用して)Webサービスと通信することになっています。このWebサービスで認証するには、クライアント証明書を提供する必要があります。前に述べたように、各クライアントには異なるクライアント証明書があり、現在のクライアントの証明書を使用する必要があります。説明されていることを実行している次のコードがあります。

X509TrustManager trustManager = new X509TrustManager() {

    public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
    }

    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
};
SSLContext sslcontext = SSLContext.getInstance("TLS");
KeyManager[] managers = /* Code that get the current client's KeyManager[] */;

sslcontext.init(managers, trustManager, null);
SSLSocketFactory socketFactory = new SSLSocketFactory(sslcontext);
socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

HttpParams params = new BasicHttpParams();
params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, true);
HttpClient client = new DefaultHttpClient(params);
Scheme sch = new Scheme("https", socketFactory, 443);

client.getConnectionManager().getSchemeRegistry().register(sch);
HttpPost post = /* Code that get the POST */ 

HttpResponse response = client.execute(post, new BasicHttpContext());

わかりました、動作しています。しかし、このサービスにリクエストを送信するスレッドはたくさんあります。時々それは私にいくつかの問題を与えます。そのため、アプリケーションごとにHttpClientを1つだけ持つ方がよいと多くの人が言っているのを見つけました。これは、次のように実行できます。

SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));

PoolingClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);
// Increase max total connection to 200
cm.setMaxTotal(200);
// Increase default max connection per route to 20
cm.setDefaultMaxPerRoute(20);
// Increase max connections for localhost:80 to 50
HttpHost localhost = new HttpHost("localhost", 80);
cm.setMaxPerRoute(new HttpRoute(localhost), 50);

httpClient = new DefaultHttpClient(cm, params);

このようにして、接続プールを備えたHttpClientを使用できます。しかし、このアプローチを使用して、特定の要求に対してクライアント証明書を選択するにはどうすればよいですか?前もって感謝します。

編集:

なぜこれをやっているのか説明しようと思います。時々問題が発生します。サーバーはWebサーバーとの通信を停止し、しばらくすると再び動作を開始します。Webサービスを呼び出す前に多くの処理が行われることに注意することが重要です。したがって、すべての処理を実行するスレッドを作成するプールされたエグゼキュータがあります。ジョブが完了すると、このスレッドはWebサービスと通信する別のスレッドを作成します。したがって、最初のスレッドはタイムアウト(thread.join(timeout))で2番目のスレッドに参加します。最初のスレッドがウェイクアップすると、まだ完了していない場合は、Webサービスと通信しようとしているスレッドに割り込んでいます。私はこれを実装した人ではありませんが、完了要求にタイムアウトを与えることになっています。私の開発マシンでは、このサービスを使用して多くのクライアントをシミュレートするJMeterテストを作成し、JConsoleを接続して何が起こっているかを確認しました。300のタスクが実行された後(そのうちのいくつかは失敗しました)、エグゼキューターのプールによって作成されたスレッドは停止しました。しかし、多くのスレッドが存続しており、10分後に死んでしまいました。スタックトレースを見ると、HttpClientに関連していることがわかりました。次に、検索を開始し、アプリケーション全体で1つのHttpClientのみを使用して、接続をプールする方がよいと言う人を見つけました。接続するポートを検索しているときにHttpClientがロックされており、最初のスレッドによって中断されていると思います。すると、どういうわけか、長時間ロックします。エグゼキュータのプールによって作成されたスレッドが停止しました。しかし、多くのスレッドが存続しており、10分後に死んでしまいました。スタックトレースを見ると、HttpClientに関連していることがわかりました。次に、検索を開始し、アプリケーション全体で1つのHttpClientのみを使用して、接続をプールする方がよいと言う人を見つけました。接続するポートを検索しているときにHttpClientがロックされており、最初のスレッドによって中断されていると思います。すると、どういうわけか、長時間ロックします。エグゼキュータのプールによって作成されたスレッドが停止しました。しかし、多くのスレッドが存続しており、10分後に死んでしまいました。スタックトレースを見ると、HttpClientに関連していることがわかりました。次に、検索を開始し、アプリケーション全体で1つのHttpClientのみを使用して、接続をプールする方がよいと言う人を見つけました。接続するポートを検索しているときにHttpClientがロックされており、最初のスレッドによって中断されていると思います。すると、どういうわけか、長時間ロックします。接続をプールします。接続するポートを検索しているときにHttpClientがロックされており、最初のスレッドによって中断されていると思います。すると、どういうわけか、長時間ロックします。接続をプールします。接続するポートを検索しているときにHttpClientがロックされており、最初のスレッドによって中断されていると思います。すると、どういうわけか、長時間ロックします。

編集:

これは私がJConsoleで見るものです。今回は、100個のタスクのみを開始し、この状態のスレッドは15個です。

Name: Thread-228
State: RUNNABLE
Total blocked: 0  Total waited: 0

Stack trace: 
 java.net.SocketInputStream.socketRead0(Native Method)
java.net.SocketInputStream.read(SocketInputStream.java:129)
com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:798)
   - locked java.lang.Object@7c1975
com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
   - locked java.lang.Object@16b53a6
com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
com.sun.net.ssl.internal.ssl.SSLSocketImpl.getSession(SSLSocketImpl.java:1916)
org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:91)
org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:692)
org.apache.http.conn.scheme.SchemeSocketFactoryAdaptor.connectSocket(SchemeSocketFactoryAdaptor.java:65)
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640)
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
sun.reflect.GeneratedMethodAccessor3671.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:229)
org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:128)
br.com.fibonacci.webservice.InvocacaoDeServico$_monteChamada_closure8.doCall(InvocacaoDeServico.groovy:441)
sun.reflect.GeneratedMethodAccessor3667.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:150)
br.com.fibonacci.webservice.InvocacaoDeServico$_monteChamada_closure8.call(InvocacaoDeServico.groovy)
sun.reflect.GeneratedMethodAccessor3662.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
br.com.fibonacci.ChamadaComTimeout$_execute_closure1.doCall(ChamadaComTimeout.groovy:19)
sun.reflect.GeneratedMethodAccessor3657.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:150)
br.com.fibonacci.ChamadaComTimeout$_execute_closure1.doCall(ChamadaComTimeout.groovy)
sun.reflect.GeneratedMethodAccessor3655.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234)
groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1061)
groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:910)
groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:892)
groovy.lang.Closure.call(Closure.java:279)
groovy.lang.Closure.call(Closure.java:274)
groovy.lang.Closure.run(Closure.java:355)
java.lang.Thread.run(Thread.java:662)
4

2 に答える 2

2

IMOは意味がないので、それは不可能だと思います。
プレーンテキストに接続を再利用することは理にかなっていますが、認証された暗号化された接続には意味がありません。 各接続はユーザーに属し、SSLパラメーターに従って終了する必要があり、ユーザー間で再利用しないでください。

于 2012-10-16T20:40:35.967 に答える
0

私の問題を説明するこのすばらしいブログ投稿http://javaeesupportpatterns.blogspot.com.br/2011/04/javanetsocketinputstreamsocketread0.htmlを見つけました。HttpClientとはあまり関係がありませんでした。問題はタイムアウトの実装にあります。

于 2012-10-17T12:58:51.507 に答える