DataOutputStream没有刷新

时间:2009-12-05 13:43:54

标签: java tcp flush dataoutputstream

我有一个Java客户端,它将UTF-8字符串发送到C#TCP-Server,我正在使用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);
        }
    }
}

问题是,冲洗似乎不正常。如果我发送两个字符串彼此接近,服务器只接收一个包含两个字符串的消息。如果我在调用之间执行Thread.sleep(1000),整个过程都有效,这显然不是解决方案。 我错过了什么?

3 个答案:

答案 0 :(得分:7)

flush()不保证数据包被发送出去。您的TCP / IP堆栈可以自由捆绑数据以实现最高效率。更糟糕的是,您和目的地之间可能存在大量其他TCP / IP堆栈,并且可以自由地执行相同操作。

我认为你不应该依赖数据包捆绑。在数据中插入逻辑终结符/分隔符,您将处于安全的一面。

答案 1 :(得分: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),因为read函数不一定读取数组的整个长度。你可以做一个循环,你一次读取一个块,但代码有点复杂。

无论如何,你明白了。


此外,如果您确实想要控制什么数据包中的内容,您可以使用Datagram Sockets,但如果您这样做,则无法保证数据包的传送。

答案 2 :(得分:1)

Socket发送数据流,而不是消息。 您不应该依赖收到的数据包与发送的数据包相同。 如您所见,数据包可以组合在一起,但它们也可以分解。 使用@Chad Okere关于如何确保在发送阻止时获得阻止的建议。

但是在你的情况下,你可以使用

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

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