8

定期的にポーリングし、特定の応答に基づいてメッセージを送信するサーバー用のJavaクライアントをセットアップしています。クラスで使用した戦略は次のとおりです。

public class PollingClient {
    private HttpClient client = getHttpClient(); // I get a DefaultHttpClient this way so it's easier to add connection manager and strategy etc to the client later
    private HttpPost httpPost = getHttpPost(); // same idea, I set headers there

    public String poll () {
        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
        formparams.add(new BasicNameValuePair("id", someId));

        String responseString = null;

        try {
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(formparams, "UTF-8");        
            httppost.setURI(polluri));
            httppost.setEntity(formEntity);
            HttpResponse response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();


            if (entity != null) {
                responseString = EntityUtils.toString(entity); 
            }

            EntityUtils.consume(entity);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void send(String msg) {
        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
        formparams.add(new BasicNameValuePair("msg", msg));
        formparams.add(new BasicNameValuePair("id", someId));

        String responseString = null;

        try {
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(formparams, "UTF-8");

            httppost.setURI(new URI(URL + "send"));
            httppost.setEntity(formEntity);

            HttpResponse response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();


            if (entity != null) {
                responseString = EntityUtils.toString(entity); 
            }

            EntityUtils.consume(entity);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

約3秒でポーリングを行うスレッドを開始します。ポーリング結果に基づいて、メインスレッドからメッセージを送信できます。コードは機能しますが、次の2つの例外が発生し続けますが、その間は機能し続けます。

java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.

org.apache.http.NoHttpResponseException: The target server failed to respond.

例外をミュートすることもできますが、何が起こっているのか知りたいです。Googleで解決策を見つけることができませんでした。私はコンテンツを消費HttpPostし、sendメソッドで新しいオブジェクトを作成しようとしましたが、これまでのところ何も役に立ちませんでした。

このような状況に適した戦略は何ですか。私は現在、問題が発生した場合に備えて、オブジェクトにkeep-aliveヘッダーを設定しています。HttpPostそれ以外は何もしていないと思います。これは戦略全体と関係があると思います。接続ごとに新しいオブジェクトを作成したくはありませんが、どのレベルの再利用が推奨されているかもわかりません。助けてくれてありがとう。ああ..これはHttpClient4.2.2です

4

4 に答える 4

1

私は以下のコードを使用することになりました。それは動作します...理由はわかりません。

DefaultHttpClient client = new DefaultHttpClient();
ClientConnectionManager mgr = client.getConnectionManager();
HttpParams params = client.getParams();
client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry()), params);
于 2012-12-20T12:28:45.530 に答える
1

@Saadの回答は非常に役に立ちましたが、多数の同時リクエストを含む単一のURLのテストをロードしようとすると、遅延が発生しました。

これが問題を解決した更新バージョンです。

    DefaultHttpClient client = new DefaultHttpClient();
    ClientConnectionManager mgr = client.getConnectionManager();
    HttpParams params = client.getParams();
    int maxConnections = 100;
    params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(maxConnections));
    params.setIntParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, maxConnections);
    ThreadSafeClientConnManager conman = new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry());
    client = new DefaultHttpClient(conman, params);
于 2014-04-08T09:53:14.077 に答える
0

これらのメソッドは同期されておらず、異なるスレッドから呼び出しています。poll()操作の進行中にコードがsend()を呼び出そうとする可能性はありますか?同じオブジェクトを使用して2つのリクエストを同時に行おうとすると、HttpClientは気に入らないと思います。

(これが問題である場合、簡単な修正は、同期されたキーワードを両方のメソッドに追加することです。ただし、それらを呼び出すスレッドをブロックしてもかまいません。)

于 2012-12-20T01:13:50.077 に答える
0

これはやり過ぎかもしれませんが、http接続の処理専用のスレッドを用意することを検討してください。このスレッドは、ポーリングするか、送信するシグナルが与えられるまでスリープ状態になります。これの利点は、1つの接続のみが使用されることです。

于 2012-12-20T04:48:52.763 に答える