是否同步PoolingClientConnectionManager

时间:2012-08-19 21:55:03

标签: java android http singleton synchronize

在我的应用程序中,多个 IntentService 以随机间隔与 Tomcat 服务器连接/通信,具体取决于用户与应用程序的交互。

我正在使用以下Singleton for 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(); 
    } 
}

除非两个IntentService同时尝试Http或者当一个连接正在进行并且另一个连接建立时,该类才能正常工作,除非它提供 connectTimeOut

代码中的一个明显改进是将已弃用的ThreadSafeClientConnManager替换为PoolingClientConnectionManager.

我应该synchronize - > public static synchronized HttpClient getHttpClient()

Singleton导致 connectTimeOut 的错误是什么?

1 个答案:

答案 0 :(得分:4)

  

是否同步PoolingClientConnectionManager?

是和否。如果你想让getHttpClient()成为一个单身人士(IMO是一个好主意),你必须使其线程安全。这需要synchronized。如果没有synchronized,则两个线程可以同时输入if块(因为customHttpClient == null对于两个线程都为真)并创建两个实例。

但是如果没有synchronized来创建线程安全的单例,那么有更好的方法(如更快)。我喜欢Singleton Holder方法。

但是不管你在这里使用的单身,你都不应该得到连接超时。如果为每个线程使用新的HttpClient实例,它也应该有用。


如果发生连接超时,则您的某个线程无法在HttpConnectionParams.setConnectionTimeout(params, 5000); = 5秒设置的时间限制内连接到服务器。

这可能有几个原因。例如,如果你处于缓慢的状态不稳定的连接可能需要更长的时间,因为您的连接可能会在几秒钟内死亡。或者,如果您的服务器由于配置而无法处理更多连接(例如,每个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来实现它,看看是否有帮助。