2013-07-11 57 views
0

我看到一些關於此的帖子,但我仍然無法找到答案。在Java套接字中關閉流的正確方法

這是我的服務器如何與客戶端的交互:

public void run() { 
    try { 
     //Read client request 
     InputStream is = server.getInputStream(); 
     byte[] buff = new byte[1024]; 
     int i; 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     while ((i = is.read(buff, 0, buff.length)) != -1) { 
      bos.write(buff, 0, i); 
      System.out.println(i + " bytes readed ("+bos.size()+")"); 
     } 
     is.close(); 
     is = null; 
     //Do something with client request 

     //write response 
     OutputStream os = server.getOutputStream(); 
     os.write("server response".getBytes()); 
     os.flush(); 
     os.close(); 
     os = null; 

    } catch (IOException ioe) { 
     ioe.printStackTrace(); 
    } 
} 

這是客戶端:

public void run() { 
     try { 
      InetAddress serverAddr = null; 
      serverAddr = InetAddress.getByName("10.0.2.2"); 
      socket = new Socket(serverAddr, 5000); 

      //Send Request to the server 
      OutputStream os = socket.getOutputStream(); 
      os.write(jsonRequest.toString().getBytes("UTF-8")); 
      os.flush(); 
      os.close(); 
      os = null; 

      //Read Server Response 
      InputStream is = socket.getInputStream(); 
      byte[] buff = new byte[1024]; 
      int i; 
      ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
      while ((i = is.read(buff, 0, buff.length)) != -1) { 
       bos.write(buff, 0, i); 
       System.out.println(i + " bytes readed ("+bos.size()+")"); 
      } 
      is.close(); 
      is = null; 

      //Do something with server response 

     } catch (UnknownHostException uhe) { 
      sendCallbackError(uhe); 
     } catch (IOException ioe) { 
      sendCallbackError(ioe); 
     } 
    } 

正如你可以看到,客戶端連接,併發送請求。服務器讀取該請求,然後寫入客戶端將讀取的響應。

此代碼的問題是客戶端中的OutputStream.close()和服務器中的InputStream.close()。正如Javadocs所述,關閉該流將關閉Socket。結果是,當客戶端嘗試讀取服務器響應時,Socket已關閉。

我已經設法通過調用Socket.shutdownInputSocket.shutdownOutput來解決這個問題。但我仍在考慮這是否是這樣做的正確方法

作爲一個說明,關閉與close()當服務器寫入響應或當客戶端讀取它時不會產生問題(我猜想關閉是在客戶端和服務器之間同步)。

所以我的問題是:

  1. 正在使用套接字關閉方法正確的方法是什麼?
  2. 我可以保留(發送和閱讀從服務器 響應時)
  3. 難道發生與關機關閉會保留一些數據 緩衝區,並且不會被髮送與close()關閉最後一個流?
+0

把socket.close()放在finally塊中。 –

+0

@PeterLawrey你的意思是不關閉流並關閉套接字?如果是,我想我應該關閉兩端的插座,對吧? – momo

+0

您應該關閉套接字,如果您想先刷新輸出流,則可能需要先關閉或刷新它。 –

回答

1

你可以做到以下幾點:

try{ 
}catch(){ 
}finally{ 
if(is!=null){ 
is.close(); 
} 
if(os!=null){ 
os.close(); 
} 
} 
+0

這是一個簡單的例子。 Streams實際上是通過run()方法調用的不同方法創建的。所以我真的無法訪問變量,除非我將它們聲明爲Runnable類的成員變量 – momo

+0

嘗試了您的建議。它不適合我,因爲如果客戶端的OutputStream沒有關閉/關閉,服務器會一直讀取。也許我應該發送一個終止序列來完成閱讀... – momo

0

這段代碼的問題是在服務器,客戶端和InputStream.close()的OutputStream.close()。正如Javadocs所述,關閉流將關閉Socket。

正確的,但在服務器中的InputStream沒有直接連接到Socket:它連接到一些你不知道任何有關。你可以不受懲罰地關閉它,儘管你根本不需要關閉它。如果您喜歡,您可以關閉服務器中的OutputStream:雖然它不是直接連接到Socket,,但它可能會或可能沒有任何其他效果,除了沖洗。

要解決您的實際問題,您不需要關閉客戶端中的輸出流,但需要發送適當的Content-Length:標頭。這樣服務器就知道從客戶端讀取多少內容。如果這只是一個GET請求,則內容長度可能爲零。你不需要撥打shutdownOutput(),,雖然我想沒有什麼可以阻止你,並且打電話shutdownInput()對網絡沒有任何作用,所以再次沒有任何意義。

+0

雖然你可能是正確的關於服務器的InputStream,如果我關閉它,然後嘗試打開OutputStream,它將失敗,並出現Socket Closed IOException。 關於Content-Length,我理解你的意思是保留字節數組的第一個字節來指定消息長度,對不對?我認爲這應該是最好的解決方案,因爲除非在服務器中關閉()OutputStream或調用socket.shutdownOutput(),否則將不會觸發服務器讀取(read()!= -1)的方式。最新的工作很好。 – momo

+0

(1)那麼不要關閉它。關閉與否與你的問題無關。 (2)不,我指的是HTTP Content-Length標頭。看看它。 – EJP

+0

這是一個普通的套接字連接,以簡單的舊字節發送JSON,這是唯一實現的協議。我不知道HTTP頭如何適合這個實現... – momo