2013-01-04 39 views
1

這不是我第一次試圖瞭解這個問題,但我希望這將是最後一個:的Java NIO的read()返回-1

一些背景:

我有一個Java SocketChannel NIO服務器工作在非阻塞模式下。

此服務器有多個客戶端,它們發送和接收來自它的消息。

每個客戶端每隔一段時間就會保持其與服務器的連接,並提供"keepalive"消息。 服務器的主要思想是客戶端將始終保持「連接」狀態,並以「推送」模式從它接收消息。

現在我的問題:

用Java NIO read()功能

- 當讀()返回-1 - 這意味着它的EOS。

在我問 here我意識到,這意味着該插座完成當前流,並不需要被關閉的問題

..

在谷歌搜索更多的關於這一點,我發現當它確實意味着連接在另一端被關閉。

  1. 「流」這個詞究竟意味着什麼?它是從客戶端發送的當前消息嗎?客戶端連接能否發送消息?

  2. 爲什麼客戶端的SocketChannel會關閉?如果客戶端從未告訴他關閉?

  3. read() return -1和通過對等I/O錯誤重置連接有什麼區別?

這是我從SocketChannel閱讀:

private JSONObject readIncomingData(SocketChannel socketChannel) 
     throws JSONException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException { 
    JSONObject returnObject = null; 
    ByteBuffer buffer = ByteBuffer.allocate(1024); 
    Charset charset = Charset.forName("UTF-8"); 
    String endOfMesesage = "\"}"; 
    String message = ""; 
    StringBuilder input = new StringBuilder();  
    boolean continueReading = true; 
    while (continueReading && socketChannel.isOpen()) 
    { 
     buffer.clear();   
     int bytesRead = socketChannel.read(buffer);    
     if (bytesRead == -1) 
     { 
      continueReading = false;      
      continue; 
     } 
     buffer.flip(); 
     input.append(charset.decode(buffer)); 
     message = input.toString(); 
     if (message.contains(endOfMesesage)) 
      continueReading = false; 
    }  
    if (input.length() > 0 && message.contains(endOfMesesage)) 
    { 
     JSONObject messageJson = new JSONObject(input.toString()); 
     returnObject = new JSONObject(encrypter.decrypt(messageJson.getString("m"))); 
    }   
    return returnObject; 
} 

回答

0

這個詞是什麼 「流」 究竟意味着什麼?它是從客戶端發送的當前消息嗎?

這是一個字節流,而不是消息流。你可以使用這些字節來形成一條消息,但是流不知道你正在做這件事,也不以任何方式支持消息。

如果客戶端沒有讓他關閉,爲什麼會在客戶端關閉SocketChannel?

如果另一端關閉它,它只能用-1關閉。

read()返回-1和通過對等I/O錯誤重置連接有什麼區別?

您可以通過其他方式關閉或刪除連接,如從同一側關閉連接,或者連接超時,例如,您拉出網線。

順便說一句:你寫代碼的方式更適合阻塞NIO。例如,如果您收到多條完整郵件,則放棄第一條郵件之後的任何郵件。如果您使用阻止IO並保留您閱讀的所有內容,則不會損壞或丟棄消息。

+0

確定,但將拉出網絡電纜返回-1或通過對等錯誤發送連接重置? 你有重新編碼的建議嗎? 爲了避免丟失消息,客戶端一次僅發送一條消息 –

+0

拉出電纜將在超時後導致異常。我建議重新編碼,以便保留所有讀取的數據,而不僅僅是您期望的數據。 read()會給你1個字節和緩衝區的最大大小。一次只發送一條消息並不意味着只會一次收到一條消息,並不能保證第一次讀取()將是一個完整的消息。 –

1

這個詞是什麼「流」究竟意味着什麼?它是從客戶端發送的當前消息嗎?客戶端連接能否發送消息?

流是指兩個地點之間流動,通常在客戶端和服務器之間,但有效的是任何類型的數據流的數據。例如。如果您從硬盤讀取文件,則使用FileInputStream代表從光盤上的文件流向程序的數據。這是一個非常通用的概念。把它想象成一個河流,水是數據。另外,這是一種非常酷的河流,它可以讓你控制水/數據的流動方式。

爲什麼會在客戶端從來沒有告訴過他的SocketChannel可以在客戶端關閉被關閉?

如果客戶端和服務器之間的連接被重置或中斷可能發生。你的程序永遠不應該假設連接只是活着而且永遠不會中斷。連接因各種原因而中斷,它可能是一個片狀網絡組件,有人拔插頭應該放在原來位置或無線網絡正在關閉。服務器也可能關閉連接,例如如果服務器程序關閉,發生錯誤或連接超時。請務必記住,開放式連接是有限的資源,因此服務器可能會在閒置時間過長時決定關閉它們。

是通過什麼對I/O錯誤read()方法返回-1和連接復位之間的區別?

當讀()返回-1這只是意味着有目前在流中沒有更多的數據。連接重置意味着可能有更多數據,但連接不再存在,因此無法再讀取這些數據。再次考慮河流學:將數據視爲從上游村莊(又稱謝維爾維爾)到下游村莊(又稱客戶維爾)的一定數量的水利用連接兩個村莊(連接)的河牀。現在Serverville有人拉動大槓桿,水(數據)從Serverville流向Clientville。在Serverville發送了所有要發送的水之後,它關閉了槓桿,河牀將再次變空(並且在連接關閉時實際上被破壞)。這是Clientville獲得-1的地方。現在想象一下推土機打斷了河牀,一些水從來沒有讓它到達凱爾特維爾。這是「連接重置」情況。

希望這有助於:)

+0

它確實幫了大忙!但仍然 - 如果我在河流類比中得到 - 1 - 水,這是否意味着這條河再也沒有水了?或者只是當前的水流結束? –

+0

1/3。(2)和(3)都不正確。除非客戶明確地「說出來」,即關閉它或退出,否則不能在客戶端關閉連接。 '通過對等方重置連接'並不表示'可能有更多的數據',這是一個協議錯誤,純粹而簡單,而且您持續的河流類比在這一點上完全不正確。 Downvoted。 – EJP

+0

是的,這條河將永遠不會再有水(這就是類比下降的地方)。如果您正在重新使用連接,但當前沒有數據可用,則讀取將返回0(即讀取了0個字節)。 –

0
  1. 這個詞是什麼 「流」 究竟意味着什麼?它是從客戶端發送的當前消息嗎?

它基本上是指連接的一側,它是全雙工的。 TCP是一種字節流協議,提供兩個獨立的字節流,每個方向一個。

  1. 爲什麼會來的SocketChannel在客戶端關閉,如果客戶端從來沒有告訴過他要關閉?

它不會。客戶確實關閉了連接。這就是read()返回-1的意思。

read()返回-1和通過對等I/O錯誤重置連接有什麼區別?

read()返回-1表示對等關閉連接正常。 '通過對等方重置連接'表示某種協議錯誤,通常是因爲您已將數據寫入到已由對等方關閉的連接。

重新編寫代碼,如果read()返回-1,則必須關閉該通道。沒有其他明智的方法可以繼續。

+0

好吧,這是有幫助的。常規套接字readLine()方法呢? 當它返回空 - 它是一樣的read()== -1? –