我的应用在不同时间连接到服务器。如果我在3g和wifi之间切换,反之亦然,我得到套接字超时错误。我该如何规避这个?我在stackoverflow上阅读了一些帖子,其中人们有类似的问题,他们通过使用新套接字来修复它。如何使用新套接字发出我的http请求?
CODE:
class HttpRunnable implements Runnable
{
private HttpRequestNotification request = null;
public HttpRunnable(HttpRequestNotification req)
{
request = req;
}
public void run()
{
HttpURLConnection conn = null;
try {
System.out.println(request.url);
conn = (HttpURLConnection)(new URL(request.url)).openConnection();
conn.setInstanceFollowRedirects(false);
conn.setRequestMethod(request.verb);
conn.setReadTimeout(20000);
conn.setConnectTimeout(20000);
// If the request contains an explicit auth token, replace our cached copy
if (request.authToken != null && request.authToken.length() > 0)
authorizationToken = request.authToken;
// Add the authorization token, if we have it
if (authorizationToken != null && authorizationToken.length() > 0)
{
conn.setRequestProperty("Authorization", authorizationToken);
}
if (request.postData != null && request.postData.length > 0)
{ // Let the connection know we'll be posting data
conn.addRequestProperty("Content-Type", "application/xml");
conn.setDoOutput(true);
}
conn.connect();
if (request.postData != null && request.postData.length > 0)
{ // Write POST data, if necessary
OutputStream os = conn.getOutputStream();
os.write(request.postData);
os.close();
}
// Grab input stream. If it hasn't occurred already, this will send the Http request over the wire.
InputStream inputStream = conn.getInputStream();
// Save off statusCode, statusMessage, headers
request.statusCode = conn.getResponseCode();
request.statusMessage = conn.getResponseMessage();
Map hdrs = conn.getHeaderFields();
Iterator iter = hdrs.keySet().iterator();
while (iter.hasNext())
{
String key = (String) iter.next();
String val = conn.getHeaderField(key);
if (key != null && val != null)
{
if (key.equalsIgnoreCase("location"))
request.url = val;
request.headers.put(key, val);
}
}
// Extract the message body. We used to extract the content-length header & only
// read that amount of bytes, but we found that sometimes the header is missing.
// Specifically, we found that requests lacked a content-length header in these cases:
// 1) for HTTP 1.1 requests that provide a "transfer-encoding: chunked" header instead
// 2) When running on certain carriers, we found the content-length header to be unreliable
// (DroidX running over Verizon -- full response body was there, but the content-length
// field was waaaay too small.
// To handle all of these cases, we simply read until the end of the stream is reached, then
// convert the result to a byte array. See defect 14288 (over WiFi, some android devices
// return Content-Length; over 3G, they may use transfer-encoding).
ByteArrayOutputStream baos = new ByteArrayOutputStream(10*1024); // This size is an initial size, not max size
while (true)
{
int data = inputStream.read();
if (data < 0)
break;
baos.write(data);
}
request.responseData = baos.toByteArray();
// Extract the auth token, if it's present
if (authorizationToken == null && request.url.endsWith("authenticate") &&
request.statusCode >= 200 && request.statusCode < 300)
{
String authToken = conn.getHeaderField("X-Authorization-Token");
if (authToken != null && authToken.length() > 0)
request.authToken = authorizationToken = authToken;
}
if (request.statusCode >= 200 && request.statusCode < 400)
{
request.onSuccess();
}
else
{
// Note -- this check is included here as well as below for future-proofing. Note that currently
// the J2SE implementation of HttpConnection will throw an IOException if the resopnse code
// is not in the 200-299 range.
if (request.statusCode == HttpURLConnection.HTTP_UNAUTHORIZED &&
!UserAuthService.HttpRequestNotification_Login.class.isInstance(request))
{ // Got a 401 Unauthorized. Since this is not a login request, we want to transition
// the user back to the login screen.
LoginOrchestrator.getInstance().logout();
}
else
request.onError(request.statusCode, "");
}
}
catch (IOException e)
{
try
{
if (conn != null)
{
request.statusCode = conn.getResponseCode();
request.statusMessage = conn.getResponseMessage();
}
}
catch (IOException ex) {}
// Have to check for this HTTP_UNAUTHRORIZED case here as well -- the J2SE HttpConnection
// throws an IOException when the status code is not in the 200-299 range.
if (request.statusCode == HttpURLConnection.HTTP_UNAUTHORIZED &&
!UserAuthService.HttpRequestNotification_Login.class.isInstance(request))
{ // Got a 401 Unauthorized. Since this is not a login request, we want to transition
// the user back to the login screen.
LoginOrchestrator.getInstance().logout();
}
else
request.onError(request.statusCode, e.toString() + ": " + e.getMessage());
}
System.out.flush();
}
}
答案 0 :(得分:1)
只需重新尝试与新套接字的连接并再次发送所有内容(在您的情况下发送新的HTTP请求)。
基本上,当您的Android设备从WiFi切换到3G时,Web服务器看到的IP地址会发生变化(从您的家庭ISP分配的IP地址到移动运营商网关IP地址)。所以旧套接字变得毫无用处......
我没有使用java.net.HttpURLConnection,但我想在超时异常时你需要重做调用serverAddress.openConnection()之后的相同代码。因为这个函数似乎是创建底层TCP连接的函数。