2009-12-05 63 views
0

我有一個Java客戶端發送UTF-8字符串到C#TCP服務器,我使用DataOutputStream發送字符串。代碼如下所示:DataOutputStream不沖洗

public void sendUTF8String(String ar) { 
    if (socket.isConnected()) { 
     try { 
      dataOutputStream.write(ar.getBytes(Charset.forName("UTF-8"))); 
      dataOutputStream.flush(); 
     } catch (IOException e) { 
      handleException(e); 
     } 
    } 
} 

問題是flush看起來沒有正常工作。如果我發送兩個相互靠近的字符串,服務器將只收到一個包含兩個字符串的消息。如果我在兩次調用之間執行Thread.sleep(1000),整個事情就會起作用,這顯然不是解決方案。 我錯過了什麼?

回答

7

flush()不保證數據包被運出。您的TCP/IP堆棧可以免費捆綁數據以獲得最大效率。更糟的是,你和你的目的地之間可能還有一堆其他的TCP/IP堆棧,他們也可以自由地做同樣的事情。

我認爲你不應該依賴數據包捆綁。在您的數據中插入一個邏輯終結器/分頻器,您將處於安全的一面。

+3

我開始迴應太多,但它只能補充說,在接收端的緩存會弄亂任何沖洗你即使你能夠可靠地衝洗,也可以在客戶端做到(一般情況下你可以)。但是不管你在客戶端做了什麼,服務器仍然會緩衝它的套接字數據。 – PSpeed 2009-12-05 13:51:27

2

您不應該擔心數據如何分解成數據包。

您應該在消息中包含字符串的長度,然後在接收端您首先會讀取長度。因此,例如送你會做

byte[] arbytes = ar.getBytes(Charset.forName("UTF-8")); 
output.writeInt(arbytes.length) 
output.write(arbytes) 

,然後在你的讀者你做

byte[] arbytes = new byte[input.readInt()]; 
for(int i = 0; i < len; i++){ 
    arbytes[i] = input.read(); 
} 
//convert bytes back to string. 

你不能只是調用input.read(arbytes),因爲讀取功能不一定讀數組的整個長度。你可以做一個循環,一次讀一個塊,但是代碼要複雜一點。

無論如何,你明白了。


此外,如果你真的控制在什麼樣的數據包發生的事情,你可以使用Datagram Sockets,但如果你這樣做,那麼傳遞的數據包不能保證。

1

套接字發送數據流,而不是消息。 您不應該依賴收到的數據包與發送的數據包大小相同。 數據包可以按照您所看到的分組在一起,但它們也可以分解。 使用@Chad Okere關於如何確保您發送塊時的建議。

不過你的情況,你可以只使用

dataOutputStream.writeUTF(ar); // sends a string as UTF-8 

String text = dataInputStream.readUTF(); // reads a string as UTF-8