2009-12-05 65 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