4

私のアプリでは、複数のIntentServiceが、ユーザーによるアプリケーションの操作に応じて、ランダムな間隔でTomcatサーバーに接続/通信します。

私はHttpに次のシングルトンを使用しています

public class CustomHttpClient { 
    private static HttpClient customHttpClient; 
    /** A private Constructor prevents instantiation */ 
    private CustomHttpClient() { 
    } 

    public static synchronized HttpClient getHttpClient() { 
        if (customHttpClient == null) { 
            HttpParams params = new BasicHttpParams(); 
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
            HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET); 
            HttpProtocolParams.setUseExpectContinue(params, true); 
            HttpProtocolParams.setUserAgent(params,"Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; Nexus One Build/FRG83)" +
                    " AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"); 
            ConnManagerParams.setTimeout(params, 1000); 
            HttpConnectionParams.setConnectionTimeout(params, 5000); 
            HttpConnectionParams.setSoTimeout(params, 10000); 
            SchemeRegistry schReg = new SchemeRegistry(); 
            schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 
            schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); 
            ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params,schReg); 
            customHttpClient = new DefaultHttpClient(conMgr, params); 
        } 
        return customHttpClient; 
    } 
    public Object clone() throws CloneNotSupportedException { 
        throw new CloneNotSupportedException(); 
    } 
}

このクラスは、2つが同時にHttpを試行するとき、または1つの接続が進行中で、別の接続が確立されるときにconnectTimeOutを提供することを除いて、正常に機能します。IntentService

ThreadSafeClientConnManagerコードの明らかな改善点の1つは、非推奨を次のように置き換えることです。PoolingClientConnectionManager.

ここにいるべきかsynchronize->public static synchronized HttpClient getHttpClient()

シングルトンのどのエラーがconnectTimeOutを引き起こしていますか?

4

1 に答える 1

4

PoolingClientConnectionManager を同期しますか?

はいといいえ。シングルトンになりたい場合getHttpClient()(IMOは良い考えです)、スレッドセーフにする必要があります。が必要synchronizedです。2 つのスレッドがなけれsynchronizedば、同時に if ブロックに入り (customHttpClient == null両方のスレッドに当てはまるため)、2 つのインスタンスを作成できます。

synchronizedしかし、スレッドセーフなシングルトンを作成せずに、より良い (より高速な) 方法があります。たとえば、シングルトンホルダーアプローチが好きです。

ただし、ここで使用するシングルトンに関係なく、接続タイムアウトは発生しません。HttpClient各スレッドに新しいインスタンスを使用する場合にも機能するはずです。


HttpConnectionParams.setConnectionTimeout(params, 5000);接続タイムアウトが発生した場合、 5 秒で設定した制限時間内にスレッドの 1 つがサーバーに接続できませんでした。

それにはいくつかの理由が考えられます。たとえば、低速で不安定な接続を使用している場合、接続が数秒間停止する可能性があるため、時間がかかる場合があります。または、構成 (IP ごとの接続制限など) が原因で、またはハードウェアがそれ以上の接続を処理できないために、サーバーがそれ以上の接続を処理できない場合も、この問題が発生する可能性があります。HttpClient基本的に、サーバーとの間でパケットを送受信することを妨げるものはすべて、その問題を引き起こす可能性があります。問題がデバイス、ネットワーク、またはサーバーのいずれかにあることを意味します。

あなたのネットワーク設定はわかりませんが、タイムアウトを増やして効果があるかどうかを確認してください。AndroidHttpClientたとえば、これらのタイムアウトを 60 秒に設定します。これは、WiFi を使用していて接続が安定している場合は必要以上ですが、接続が非常に弱い場合は問題ありません。

AndroidHttpClient適用される他の設定が役立つかどうかを確認することもできます。

AndroidHttpClient以下の設定

// Default connection and socket timeout of 60 seconds.  Tweak to taste.
private static final int SOCKET_OPERATION_TIMEOUT = 60 * 1000;

// ---------------------------------------------------------------------- //
HttpParams params = new BasicHttpParams();

// Turn off stale checking.  Our connections break all the time anyway,
// and it's not worth it to pay the penalty of checking every time.
HttpConnectionParams.setStaleCheckingEnabled(params, false);

HttpConnectionParams.setConnectionTimeout(params, SOCKET_OPERATION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, SOCKET_OPERATION_TIMEOUT);
HttpConnectionParams.setSocketBufferSize(params, 8192);

// Don't handle redirects -- return them to the caller.  Our code
// often wants to re-POST after a redirect, which we must do ourselves.
HttpClientParams.setRedirecting(params, false);

// Use a session cache for SSL sockets
SSLSessionCache sessionCache = context == null ? null : new SSLSessionCache(context);

// Set the specified user agent and register standard protocols.
HttpProtocolParams.setUserAgent(params, userAgent);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http",
        PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https",
        SSLCertificateSocketFactory.getHttpSocketFactory(
        SOCKET_OPERATION_TIMEOUT, sessionCache), 443));

ClientConnectionManager manager =
        new ThreadSafeClientConnManager(params, schemeRegistry);

return new DefaultHttpClient(manager, params);

問題がどこにあるかを判断するには、サーバー接続ログを調べて、デバイスが接続を開始しようとしているかどうか、接続が確立されていない理由があるかどうかを確認します。タイムアウトが発生したときに接続試行が表示されない場合は、デバイスまたはネットワークの問題である可能性が高くなります。

デバイスが接続されているネットワーク (= WiFi) にアクセスできる場合は、Wiresharkなどでネットワーク トラフィックをチェックして、接続の試行がタイムアウトした理由を調べることができます。デバイスが接続要求を送信するかどうかを確認できます。

最後になりましたが、コードの一部が原因である可能性があります。他の解決策が見つからない場合は、それを実装してみて、HttpURLConnectionそれが役立つかどうかを確認してください。

于 2012-08-20T21:06:21.990 に答える