使用http的Android IOException ...但它仍然有效

时间:2012-02-09 01:43:19

标签: android httpclient

我正在使用httpclient与Web服务器通信,但我偶尔会遇到IOException,但奇怪的是,该命令仍然会进入Web服务器。实际上,我甚至通常从服务器获得有效的数据响应以及IOException。我该如何处理IOExceptions?

这是我的代码,万一它是我做错的事情:

DefaultHttpClient client = new DefaultHttpClient();
CookieSyncManager.getInstance().startSync();
HttpContext localContext = new BasicHttpContext();

String password = db.getWebPassword();
String username = db.getWebUsername();

HttpGet httpGet = new HttpGet(url);

final HttpParams httpParams = client.getParams();

// try playing with the timesouts, but I don't think I know what I am doing...
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, 5000);

Integer responseCode = 0;
try 
{
    HttpResponse execute;
    UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
    client.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), creds);
    execute = client.execute(httpGet);
    HttpEntity entity = execute.getEntity(); // often catches an IOException here     
    Log.d(MY_DEBUG_TAG, "Execute complete: " + entity.toString());
    responseCode = execute.getStatusLine().getStatusCode();
    Log.d(MY_DEBUG_TAG, "Response Code: " + responseCode);
    if (responseCode == 401)
    {
         response = "ERROR";
     Toast.ShowToast("Username/Password error.", pa);
    }

    InputStream content = execute.getEntity().getContent();

    Log.d(MY_DEBUG_TAG, "Reading response");
    BufferedReader buffer = new BufferedReader(
              new InputStreamReader(content));
    String s = "";
    while ((s = buffer.readLine()) != null) 
    {
         response += s;
    }
    // remove all html if possible
    response = android.text.Html.fromHtml(response).toString();
    Log.d(MY_DEBUG_TAG, "Response = " + response);
}
catch (ClientProtocolException e) 
{
     Log.e(MY_ERROR_TAG, "ClientProtocolException: " + e.getMessage());
     Toast.ShowToast("Error connecting to server.", pa);
}
catch (IOException e)
{
       Log.e(MY_ERROR_TAG, "IOException: " + e.getMessage());
     Toast.ShowToast("Error connecting to server.", pa);
}

根据请求添加堆栈跟踪:

java.net.SocketTimeoutException
    at org.apache.harmony.luni.net.PlainSocketImpl.read(PlainSocketImpl.java:564)
    at org.apache.harmony.luni.net.SocketInputStream.read(SocketInputStream.java:88)
    at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:103)
    at org.apache.http.impl.io.AbstractSessionInputBuffer.readLine(AbstractSessionInputBuffer.java:191)
    at org.apache.http.impl.conn.DefaultResponseParser.parseHead(DefaultResponseParser.java:82)
    at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:174)
    at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:179)
    at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:235)
    at org.apache.http.impl.conn.AbstractClientConnAdapter.receiveResponseHeader(AbstractClientConnAdapter.java:259)
    at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:279)
    at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:121)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:410)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
    at com.PowerHomeConnectorForAndroid.Network$GetHttpData.doInBackground(Network.java:215)
    at com.PowerHomeConnectorForAndroid.Network$GetHttpData.doInBackground(Network.java:1)
    at android.os.AsyncTask$2.call(AsyncTask.java:185)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
    at java.lang.Thread.run(Thread.java:1096)

请记住,这里的问题是我正在捕获异常,但代码仍然有效,我可以看到服务器收到命令,我甚至从服务器得到响应。

我做了一些wirehark嗅探,一个好的会话和糟糕的会话看起来几乎完全相同,除了最终响应回到手机所需的时间。由于异常实际上是一个SocketTimeoutException,我认为这是有道理的,但实际情况是响应确实使它恢复并且手机接受它作为同一会话的一部分,那么真正发生了什么?有没有例外?

这里有wireshark捕获(对不起左右滚动)第一次捕获是坏会话,第二次捕获是好会话。

      IOException                                                                                                                                                           x     Good                              
1     http-alt     0             70.165.69.220     192.168.1.110     TCP     66     20180 > http-alt [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1                 x     31     http-alt     0            70.165.69.220     192.168.1.110     TCP     66     52220 > http-alt [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1
2     20180        0.000039      192.168.1.110     70.165.69.220     TCP     66     http-alt > 20180 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1      x     32     52220        0.000043     192.168.1.110     70.165.69.220     TCP     66     http-alt > 52220 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1
3     http-alt     0.05784       70.165.69.220     192.168.1.110     TCP     60     20180 > http-alt [ACK] Seq=1 Ack=1 Win=65536 Len=0                                      x     33     http-alt     0.22131      70.165.69.220     192.168.1.110     TCP     60     52220 > http-alt [ACK] Seq=1 Ack=1 Win=65536 Len=0
4     http-alt     0.153949      70.165.69.220     192.168.1.110     HTTP   196     GET /ph-cgi/clogin HTTP/1.1                                                             x     34     http-alt     0.350917     70.165.69.220     192.168.1.110     HTTP   196     GET /ph-cgi/clogin HTTP/1.1 
5     20180        0.161902      192.168.1.110     70.165.69.220     HTTP  2967     HTTP/1.0 200 OK  (text/html)                                                            x     35     52220        0.3841       192.168.1.110     70.165.69.220     HTTP  2967     HTTP/1.0 200 OK  (text/html)
6     20180        0.161992      192.168.1.110     70.165.69.220     TCP     54     http-alt > 20180 [FIN, ACK] Seq=2914 Ack=143 Win=65536 Len=0                            x     36     52220        0.38419      192.168.1.110     70.165.69.220     TCP     54     http-alt > 52220 [FIN, ACK] Seq=2914 Ack=143 Win=65536 Len=0
7     http-alt     0.209671      70.165.69.220     192.168.1.110     TCP     60     20180 > http-alt [ACK] Seq=143 Ack=1461 Win=65536 Len=0                                 x     37     http-alt     0.614323     70.165.69.220     192.168.1.110     TCP     60     52220 > http-alt [ACK] Seq=143 Ack=1461 Win=65536 Len=0
8     http-alt     0.253024      70.165.69.220     192.168.1.110     TCP     60     20180 > http-alt [ACK] Seq=143 Ack=2915 Win=64000 Len=0                                 x     38     http-alt     0.614456     70.165.69.220     192.168.1.110     TCP     60     52220 > http-alt [ACK] Seq=143 Ack=2915 Win=64000 Len=0
9     http-alt     0.373148      70.165.69.220     192.168.1.110     TCP     60     20180 > http-alt [FIN, ACK] Seq=143 Ack=2915 Win=64000 Len=0                            x     39     http-alt     0.746923     70.165.69.220     192.168.1.110     TCP     60     52220 > http-alt [FIN, ACK] Seq=143 Ack=2915 Win=64000 Len=0
10    20180        0.373172      192.168.1.110     70.165.69.220     TCP     54     http-alt > 20180 [ACK] Seq=2915 Ack=144 Win=65536 Len=0                                 x     40     52220        0.746944     192.168.1.110     70.165.69.220     TCP     54     http-alt > 52220 [ACK] Seq=2915 Ack=144 Win=65536 Len=0
11    http-alt     0.38402       70.165.69.220     192.168.1.110     TCP     66     53091 > http-alt [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1                 x     41     http-alt     0.762482     70.165.69.220     192.168.1.110     TCP     66     64314 > http-alt [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1
12    53091        0.384069      192.168.1.110     70.165.69.220     TCP     66     http-alt > 53091 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1      x     42     64314        0.762517     192.168.1.110     70.165.69.220     TCP     66     http-alt > 64314 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1
13    http-alt     0.425956      70.165.69.220     192.168.1.110     TCP     60     53091 > http-alt [ACK] Seq=1 Ack=1 Win=65536 Len=0                                      x     43     http-alt     1.015043     70.165.69.220     192.168.1.110     TCP     60     64314 > http-alt [ACK] Seq=1 Ack=1 Win=65536 Len=0
14    http-alt     0.511349      70.165.69.220     192.168.1.110     TCP    349     [TCP segment of a reassembled PDU]                                                      x     44     http-alt     1.064351     70.165.69.220     192.168.1.110     TCP    349     [TCP segment of a reassembled PDU]
15    53091        0.704456      192.168.1.110     70.165.69.220     TCP     54     http-alt > 53091 [ACK] Seq=1 Ack=296 Win=65536 Len=0                                    x     45     64314        1.263922     192.168.1.110     70.165.69.220     TCP     54     http-alt > 64314 [ACK] Seq=1 Ack=296 Win=65536 Len=0
16    http-alt     2.562688      70.165.69.220     192.168.1.110     HTTP    99     POST /ph-cgi/cauth HTTP/1.1  (application/x-www-form-urlencoded)                        x     46     http-alt     3.088689     70.165.69.220     192.168.1.110     HTTP    99     POST /ph-cgi/cauth HTTP/1.1  (application/x-www-form-urlencoded)
17    53091        2.567888      192.168.1.110     70.165.69.220     HTTP   355     HTTP/1.0 200 OK  (text/html)                                                            x     47     64314        3.093318     192.168.1.110     70.165.69.220     HTTP   355     HTTP/1.0 200 OK  (text/html)
18    53091        2.568447      192.168.1.110     70.165.69.220     TCP     54     http-alt > 53091 [FIN, ACK] Seq=302 Ack=341 Win=65536 Len=0                             x     48     64314        3.093858     192.168.1.110     70.165.69.220     TCP     54     http-alt > 64314 [FIN, ACK] Seq=302 Ack=341 Win=65536 Len=0
19    http-alt     2.612071      70.165.69.220     192.168.1.110     TCP     60     53091 > http-alt [ACK] Seq=341 Ack=303 Win=65280 Len=0                                  x     49     http-alt     3.313276     70.165.69.220     192.168.1.110     TCP     60     64314 > http-alt [ACK] Seq=341 Ack=303 Win=65280 Len=0
20    http-alt     2.665338      70.165.69.220     192.168.1.110     TCP     66     34654 > http-alt [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1                 x     50     http-alt     3.410808     70.165.69.220     192.168.1.110     TCP     66     33703 > http-alt [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1
21    34654        2.665385      192.168.1.110     70.165.69.220     TCP     66     http-alt > 34654 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1      x     51     33703        3.410851     192.168.1.110     70.165.69.220     TCP     66     http-alt > 33703 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1
22    http-alt     2.665487      70.165.69.220     192.168.1.110     TCP     60     53091 > http-alt [FIN, ACK] Seq=341 Ack=303 Win=65280 Len=0                             x     52     http-alt     3.41086      70.165.69.220     192.168.1.110     TCP     60     64314 > http-alt [FIN, ACK] Seq=341 Ack=303 Win=65280 Len=0
23    53091        2.6655        192.168.1.110     70.165.69.220     TCP     54     http-alt > 53091 [ACK] Seq=303 Ack=342 Win=65536 Len=0                                  x     53     64314        3.41087      192.168.1.110     70.165.69.220     TCP     54     http-alt > 64314 [ACK] Seq=303 Ack=342 Win=65536 Len=0
24    http-alt     2.709857      70.165.69.220     192.168.1.110     TCP     60     34654 > http-alt [ACK] Seq=1 Ack=1 Win=65536 Len=0                                      x     54     http-alt     3.715974     70.165.69.220     192.168.1.110     TCP     60     33703 > http-alt [ACK] Seq=1 Ack=1 Win=65536 Len=0
25    http-alt     2.916243      70.165.69.220     192.168.1.110     HTTP   308     GET /ph-cgi/eval?formula=ph_macro%28%27TESTING%27%29 HTTP/1.1                           x     55     http-alt     3.830971     70.165.69.220     192.168.1.110     HTTP   308     GET /ph-cgi/eval?formula=ph_macro%28%27TESTING%27%29 HTTP/1.1 
26    34654        3.114457      192.168.1.110     70.165.69.220     TCP     54     http-alt > 34654 [ACK] Seq=1 Ack=255 Win=65536 Len=0                                    x     56     33703        3.858623     192.168.1.110     70.165.69.220     HTTP   153     HTTP/1.0 200 OK  (text/html)
27    http-alt     11.023287     70.165.69.220     192.168.1.110     TCP     60     34654 > http-alt [FIN, ACK] Seq=255 Ack=1 Win=65536 Len=0                               x     57     33703        3.858729     192.168.1.110     70.165.69.220     TCP     54     http-alt > 33703 [FIN, ACK] Seq=100 Ack=255 Win=65536 Len=0
28    34654        11.023305     192.168.1.110     70.165.69.220     TCP     54     http-alt > 34654 [ACK] Seq=1 Ack=256 Win=65536 Len=0                                    x     58     http-alt     4.114668     70.165.69.220     192.168.1.110     TCP     60     33703 > http-alt [ACK] Seq=255 Ack=101 Win=65536 Len=0
29    34654        34.882577     192.168.1.110     70.165.69.220     TCP     54     http-alt > 34654 [FIN, ACK] Seq=1 Ack=256 Win=65536 Len=0                               x     59     http-alt     4.153392     70.165.69.220     192.168.1.110     TCP     60     33703 > http-alt [FIN, ACK] Seq=255 Ack=101 Win=65536 Len=0
30    http-alt     34.926041     70.165.69.220     192.168.1.110     TCP     60     34654 > http-alt [ACK] Seq=256 Ack=2 Win=65536 Len=0                                    x     60     33703        4.153402     192.168.1.110     70.165.69.220     TCP     54     http-alt > 33703 [ACK] Seq=101 Ack=256 Win=65536 Len=0

所以,也许我应该忽略一个SocketTimeoutException ???听起来很危险....

1 个答案:

答案 0 :(得分:2)

我认为问题在于你在这一行中的套接字超时:

HttpConnectionParams.setSoTimeout(httpParams, 5000);

如果我们查看HttpClient文档的这一部分:http://hc.apache.org/httpclient-legacy/exception-handling.html

例如,如果HTTP服务器成功接收并处理请求,生成响应并将状态代码发送回客户端,则HTTP服务器将考虑合同的一部分。如果客户端由于读取超时,请求取消或系统崩溃而未能完全接收响应,则服务器将不会尝试回滚事务。如果客户端决定重试相同的请求,则服务器将不可避免地多次执行同一事务。在某些情况下,这可能会导致应用程序数据损坏或应用程序状态不一致。

服务器正在接收请求并发送响应的事实可能是文档描述的内容。解决方案是增加SoTimeout或重试您的请求:

HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler(){
        @Override
        public boolean retryRequest(IOException exception,
                int executionCount, HttpContext context) {

            if (executionCount >= 5) {
                Log.e("Retry Limit", "Retry #: " + executionCount);
                return false;
            }

            if(exception instanceof java.net.SocketTimeoutException){
                Log.e("(SocketTimeoutException)", "Retry #: " + executionCount);
                return true;
            }
            if(exception instanceof java.net.SocketException){
                Log.e("(SocketException)", "Retry #: " + executionCount);
                return true;
            }
            if(exception instanceof ObjectStreamException){
                Log.e("(ObjectStreamException)", "Retry #: " + executionCount);
                return true;
            }
            if(exception instanceof ProtocolException){
                Log.e("(ProtocolException)", "Retry #: " + executionCount);
                return true;
            }
            if(exception instanceof SSLException){
                Log.e("(SSLException)", "Retry #: " + executionCount);
                return true;
            }
            if(exception instanceof SyncFailedException){
                Log.e("(SyncFailedException)", "Retry #: " + executionCount);
                return true;
            }
            if(exception instanceof UTFDataFormatException){
                Log.e("(UTFDataFormatException)", "Retry #: " + executionCount);
                return true;
            }
            return false;
        }
    };
    client.setHttpRequestRetryHandler(retryHandler);

这会捕获SocketTimeOut,SocketException等。但是如果你得到IOException,你可以手动重试请求:

catch (IOException e)
{
    SystemClock.sleep(1500);
       Log.e(MY_ERROR_TAG, "IOException: " + e.getMessage());
     Toast.ShowToast("Error connecting to server.", pa);
    /*RETRY THE REQUEST MANUALLY*/
}