2016-04-06 80 views
3

在我的項目中,有一臺服務器爲客戶端服務併爲其提供服務。服務器在客戶端斷開連接後收到消息

服務器----主

ss = new ServerSocket(12345); 
    System.out.println("Server started.."); 
    while(true) 
    { 
     System.out.println("Waiting For clients..."); 
     Socket client = ss.accept(); 
     System.out.println("Got client..."); 
     Thread t = new Thread(new Handler(client)); 
     t.start(); 
     //exe.execute(new Handler(client)); 

    } 

這是主要方法,服務器創建一個無限循環(螺紋),將接受輸入連接。一旦接收到連接,服務器將創建一個新的Handler對象,該對象將連接的客戶端作爲參數。

處理程序類

public class Handler implements Runnable { 

    Socket client; 

    public Handler(Socket client) { 
     // TODO Auto-generated method stub 
     this.client = client; 
    } 
    @Override 
    public void run() { 
     // TODO Auto-generated method stub 
     //streams 
     try { 
      OutputStream out = client.getOutputStream(); 
      PrintWriter writer = new PrintWriter(out); 

      InputStream in = client.getInputStream(); 
      BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 

      String s = null; 

      while((s=reader.readLine())!=null) 
      { 

       //will switch on string or convert to json object 
       System.out.println("Recieved: " + s); 
      } 
      writer.close(); 
      reader.close(); 
      client.close(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

    } 

} 

在這個類的主要目的是處理客戶請求。所以構造函數將套接字對象初始化爲它自己的實例。

在run方法中實例化對象,然後有一個無限循環,假設打印來自客戶端的任何傳入消息。

當客戶端斷開連接時,循環將中斷,並且這是調用方法的地方,以正常關閉和釋放資源。由此線程結束。

客戶 - (安卓)

public class MainActivity extends AppCompatActivity { 

    final String ip = "192.168.0.18"; 
    final int port = 12345; 
    Socket client; 
    OutputStream out; 
    PrintWriter writer; 

    InputStream in; 
    BufferedReader reader; 
    final String TAG = "Debug: "; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     new ConnectToServer().execute(); 
     new SendToServer().execute(); 


    } 

    class ConnectToServer extends AsyncTask<Void, Void, Void> 
    { 

     @Override 
     protected Void doInBackground(Void... params) 
     { 
      try { 
       client = new Socket(ip,port); 
       //Log.d(TAG, "doInBackground: connected to server"); 
       //set streams 
       out = client.getOutputStream(); 
       writer = new PrintWriter(out); 

       in = client.getInputStream(); 
       reader = new BufferedReader(new InputStreamReader(in)); 

       Log.d(TAG, "doInBackground: Sent"); 



      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      return null; 
     } 
    } 
    class SendToServer extends AsyncTask<Void, Void, Void> 
    { 

     @Override 
     protected Void doInBackground(Void... params) { 
      writer.write("lol"); 
      writer.flush(); 
      return null; 
     } 
    } 

} 

我最後一次與Android Studio中扮演一年前左右,我非常積極的網絡/ IO操作都可以對主線程上運行。但是黃金法則意味着不阻塞主線程,並且有一些阻塞方法。

我選擇使用AsyncTask接口,因爲它封裝了更低層次的Thread類(更易於使用/瞭解我的生命週期)。

ConnectToServer類成功連接到服務器,但一旦調用SendToServer類,服務器就不會收到消息。

一旦我斷開客戶端(終止應用程序),服務器將打印出消息。

爲什麼服務器在客戶端斷開連接後收到消息?

+0

爲什麼你有兩個異步任務? – Pooya

+0

@Pooya從我的理解,我沒有關閉連接。當Android客戶端終止應用程序時,連接關閉。當應用程序關閉時,它將向服務器返回一個0或-1,並且BufferedReader對象將讀取並跳出循環,然後關閉流和套接字。 – Moynul

+0

@Pooya一個AsyncTask用於連接服務器,另一個AsynTask是將數據發送到服務器。 – Moynul

回答

1

您正在閱讀的文章,但您並未撰寫文章。在正在發送的消息中添加一個行結束符,或使用println()而不是write()

+0

你說我正在讀取服務器上的行。 BufferedReader對象使用readLine()方法來讀取我想要的傳入數據包? 我不明白你的意思是「添加行終止符到正在發送的消息」,但是使用printLn()方法確實有效。我不明白爲什麼要使用「寫入」方法。我將看看API文檔。 – Moynul

+0

我不知道你期望一個叫做'readLine()'的方法來做什麼,但是它會讀取一行。行結束符是「\ r \ n」,「\ r」或「\ n」或「System.lineSeparator()」。 'println((''添加一個行結束符,所有這些都在Javadoc中。 – EJP

相關問題