2011-11-10 17 views
1

私のアプリはさまざまな時にサーバーに接続します。 3gとwifiの間で切り替えると、ソケットタイムアウトエラーが発生します。これを回避するには?私は人々が同様の問題を抱えていたstackoverflowのいくつかの記事を読んで、新しいソケットを使って修正しました。新しいソケットでhttpリクエストを作成するにはどうしたらいいですか?3Gと無線LANを切り替えるとAndroid Socketエラーが発生する

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

org.apache.http.client.HttpClientを使用していますか? –

+0

java.net.HttpURLConnection; – spentak

答えて

1

ただ、新しいソケットとの接続を再試行して(あなたのケースで新しいHTTPリクエストを送信する)、再びすべてを送ります。

基本的には、AndroidデバイスがWiFiから3Gに切り替わると、Web Serverが認識するIPアドレスが自宅のISPから割り当てられたIPアドレスからモバイルキャリアのゲートウェイIPアドレスに変更されます。したがって、古いソケットは役に立たなくなります...

私はjava.net.HttpURLConnectionを使用していませんが、timeout例外では、serverAddress.openConnection()を呼び出した後のコードと同じコードをやり直す必要があります。この機能は、基本的なTCP接続を作成するものと思われるためです。

+0

新しいソケットとの接続についてちょっと説明できますか?私はまだhttprequests/javaについて学んでいます。私が単純にリクエストをやり直すと、タイムアウトエラーが発生します。具体的には新しいソケットを使用するために実際にコード内で何をしなければなりませんか? – spentak

+0

@spentak、コードを投稿できますか? –

+0

上記の投稿を参照してください - – spentak

関連する問題