我正在使用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 ???听起来很危险....
答案 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*/
}