2013-01-07 86 views
1

我編寫了一個Android套接字演示程序,它只是將用戶輸入發佈到服務器。 我通過wifi連接從android客戶端建立socket,一切順利,服務器端可以收到android客戶端發送的消息。問題是,然後關閉手機的WIFI,但套接字可以毫無例外地寫入。當wifi連接斷開時,Android套接字仍然可以正常寫入

Android客戶端的代碼:

public class MyActivity extends Activity { 
    private SocketHandlerThread thread; 

    /** 
    * Called when the activity is first created. 
    */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     thread = new SocketHandlerThread("ScoketTest"); 
     thread.start(); 
    } 

    class SocketHandlerThread extends HandlerThread { 
     private Socket socket; 
     private Handler handler; 

     public SocketHandlerThread(String name) { 
      super(name); 
     } 

     public SocketHandlerThread(String name, int priority) { 
      super(name, priority); 
     } 

     @Override 
     public void run() { 
      try { 
       socket = new Socket("192.168.60.184", 1990); 
      } catch (IOException e) { 
       Log.e("SocketTest", e.getLocalizedMessage(), e); 
      } 
      super.run(); 
     } 

     Handler getHandler() { 
      if (handler == null) { 
       handler = new Handler(getLooper()); 
      } 
      return handler; 
     } 

     void send(final String text) { 
      Runnable runnable = new Runnable() { 
       public void run() { 
        Log.e("SocketTest", "Start send text: " + text); 
        try { 
         socket.getOutputStream().write((text + "\n").getBytes()); 
         socket.getOutputStream().flush(); 
        } catch (Exception e) { 
         Log.e("SocketTest", e.getLocalizedMessage(), e); 
        } 
        Log.e("SocketTest", "Text has been send:" + text); 
       } 
      }; 
      getHandler().post(runnable); 
     } 

     @Override 
     protected void onLooperPrepared() { 
      runOnUiThread(new Runnable() { 
       @Override 
       public void run() { 
        findViewById(R.id.button).setEnabled(true); 
       } 
      }); 
     } 
    } 

    public void send(View view) { 
     String text = ((EditText) findViewById(R.id.text)).getText().toString(); 
     thread.send(text); 
    } 
} 

服務器的代碼:

public class SocketTestServer { 
    ServerSocket serverSocket; 

    SocketTestServer() throws IOException { 
     serverSocket = new ServerSocket(1990); 
    } 

    void start() throws IOException { 
     Socket clientSocket = serverSocket.accept(); 
     clientSocket.getInputStream(); 
     PrintWriter out = new PrintWriter(System.out, true); 
     BufferedReader in = 
       new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
     String inputLine; 
     while ((inputLine = in.readLine()) != null) { 
      out.println(inputLine); 
     } 
    } 

    public static void main(String[] args) throws IOException { 
     SocketTestServer server = new SocketTestServer(); 
     server.start(); 
    } 
} 

我嘗試幾個電話。在Galaxy Nexus(4.2.1)上拋出了一個預期的異常,但在某些MOTO或HTC手機上,套接字仍然可以毫無例外地寫入,這意味着我可能會丟失一些我認爲已成功接收的消息。 我怎麼能知道在任何類型的手機上的套接字連接被破壞?

任何建議將不勝感激。

p.s 我知道Connective Change Broadcast,但在接收廣播之前,客戶端可能會通過破損的套接字寫入一些消息。

儘管在應用協議上增加接收檢查可以解決郵件丟失問題,但我更願意保證TCP協議承諾的傳輸層的可靠性。

回答

0

我使用Writer & IOException在我的套接字,它工作正常。試試這個:

public static void sendUTF(String str) 
    { 
     try 
     { 
      outWriter.write(str + '\n'); 
      outWriter.flush(); 
     } 
     catch (IOException e) 
     { 
      e.printStackTrace(); 
      outServ.setText("Connection lost!"); 
     } 
    } 

public static Writer outWriter = new OutputStreamWriter(outputStream, "UTF-8"); 
0

這是TCP堆棧(OS級)問題,是難以解決的問題。 如果服務器失去連接(嘗試在打開套接字後重新啓動服務器並且沒有客戶端會注意到),它也會發生......您將在下次通過套接字發送數據包時遭受「斷開的管道錯誤」 。

因此,有兩種方案:

1-當客戶端發送信息破管。

在這種情況下,您應該捕獲IOException並重試以打開連接(您將必須定義重試策略)。

2-水管壞了,當服務器失去連接

當服務器失去連接的客戶端沒有注意到的話,在這種情況下,你應該定期(輪詢技術)數據包發送給服務器,並嘗試在連接丟失的情況下重新連接。 如果您從服務器接收到更新,則需要這樣做,如果您的流量始終是客戶端 - >服務器,則僅適用方案1。