4

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

我正在为 Http 使用以下 Singleton

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(); 
    } 
}

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

代码中一项明显的改进是将 deprecated 替换ThreadSafeClientConnManagerPoolingClientConnectionManager.

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

Singleton 中的什么错误导致connectTimeOut

4

1 回答 1

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看看是否有帮助。

于 2012-08-20T21:06:21.990 回答