2011-03-30 78 views
1

問題:損壞的TCP段。SocketChannel.write(ByteBuffer [])「破壞」數據

我在SocketChannel中反覆發送一個ByteBuffers序列。該順序如下:

\r\n 
length of chunk (example: fff) 
\r\n 
chunk data (rubbish, a 1000 - 5000 character long string) 
\r\n 
length of next chunk (example: fff) 
\r\n 
next chunk data (rubbish, a 1000 - 5000 character long string) 

...

我希望你看到的格局。網絡級別的MTU大約是1500,所以它會創建TCP段來發送「塊數據」。

段中的問題是:以某種方式(?),隨機地(?),段(其有效載荷)首先以\ r \ n開頭,而不是先從「塊數據」中剩餘的字節開始。

所以,你得到例如:

(segment 1) 
\r\n 
length of chunk (example: fff) 
\r\n 
chunk data (456 bytes) 

(segment 2) 
\r\n 
chunk data (remaining 156 bytes) 
length of next 
\r\n 

相反的:

(segment 1) 
\r\n 
length of chunk (example: fff) 
\r\n 
chunk data (456 bytes) 

(segment 2) 
chunk data (remaining 156 bytes) 
\r\n 
length of next 
\r\n 

我想知道,如果Java代碼甚至能引起的是,知道我的「塊數據」 ByteBuffer正確發送,除了包含\ r \ n的ByteBuffer加入... 歡迎任何幫助,謝謝你的時間!

Andrew

+3

我們看一些代碼。問題不大可能出現在Java庫,操作系統或網絡級別。 – NPE 2011-03-30 15:23:29

+0

感謝您的回覆,但我目前只是在查找「已知問題」,因爲SocketChannel在到達使用寫入點(ByteBuffer [])之前經過了大約20個類:-( – AndrewBourgeois 2011-03-30 15:39:58

+0

)數據如何排列ByteBuffer。我認爲每個ByteBuffer都包含一個帶有標題的完整消息,因此不可能改變數據的順序。 – 2011-03-30 15:46:37

回答

3

我敢打賭,你忽略了讀或寫的結果。 TCP不會丟失或損壞數據,Socket API或Java網絡庫也不會。至少我在22年的網絡編程和14年的Java中從未見過它。

+0

+1 - 錯誤率爲99.9999%,可能在OP的代碼中...不在網絡中stacks/Java類庫 – 2011-03-31 00:50:50

+0

你是正確的,從ByteBuffer []到SocketChannel的傳輸是在for循環中完成的,只有在for循環之後,其餘的字節才被寫入SocketChannel。索引爲3的ByteBuffer沒有返回「清空」,在我們編寫剩餘字節之前,下一個ByteBuffer可能已經被寫入了。PS:該bug位於SourceForge上的AdaptIt庫中。感謝您的幫助! – AndrewBourgeois 2011-04-01 13:56:36

0

這不是因爲網絡問題,而是因爲我們編碼的方式。如果我們正在以塊讀取和寫入數據,則可能導致數據因上一個塊而損壞。最後的數據塊讀取可能部分被填充,並且字節數組的默認值爲0。 以下示例顯示了它

ObjectOutputStream out = new ObjectOutputStream(
       socket.getOutputStream()); 
ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); 
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); 
//Something local returns DataInputStream from server 
InputStream dataInputStream = local.downloadFile(fileToBeRead); 
int chunkSize = 10000; 
byte[] chunkByteArray = new byte[chunkSize]; 
int bytesRead = -1; 
while ((bytesRead = dataInputStream.read(chunkByteArray)) != -1) { 
    if (bytesRead < chunkSize) { 
     System.out.println("Last Chunk is " + bytesRead); 
     chunkByteArray = getLastChunkByteArray(bytesRead,chunkByteArray); 
    } 
    out.write(chunkByteArray); 
} 
      dataInputStream.close(); 

溶液和方法

private byte[] getLastChunkByteArray(int noOfBytesRead, 
     byte[] partialFilledChunk) { 

    byte[] lastChunk = new byte[noOfBytesRead]; 
    for (int i = 0; i < noOfBytesRead; i++) { 
     lastChunk[i] = partialFilledChunk[i]; 
    } 
    return lastChunk; 
}