为什么 Java writeBytes 方法在第一个 TCP 数据包中只发送一个字节而 write 方法不发送?

Why does Java writeBytes method send only one byte in first TCP packet and write method does not?

我在 java 中开发了一个简单的客户端(我使用 Windows 7 机器)来与服务器通信。问题是服务器从来不理解我的请求。所以我分析了与 Wireshark 的通信并注意到第一个 TCP 数据包中只发送一个字节,其余字节在另一个数据包中发送 40 毫秒后。

事实上,我们是用二进制帧来通信的,所以所有的帧都必须以帧的总长度为2字节开始。所以服务器永远不会理解我是正常的。我所有的帧都不会超过 10 个字节,所以这是一个微不足道的数据量。我知道 TCP 数据包可以被分割,但对我来说,只分割一个字节后的一个小帧是没有意义的。

经过几个小时的研究失败后,我随便尝试使用 write 方法而不是 writeBytes 方法以其他方式发送字节。现在我只在一个 TCP 数据包中发送所有数据并且通信正常,但我从未找到解释。如果有人知道,我会很乐意学习。

这是我的代码:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;

public class Client {

public static void main(String argv[]) {

    try {
        Socket socket = new Socket();
        socket.connect(new InetSocketAddress("10.2.1.1", 1003), 1000);
        DataOutputStream outToServer = new DataOutputStream(socket.getOutputStream());
        DataInputStream inFromServer = new DataInputStream(socket.getInputStream());

        // Hexadecimal frame to send to server
        String hexFrame = "0004FF9D3175";

        // Build bytes frame
        String bytesFrame = "";
        for (int i=0; i<hexFrame.length()/2; i++) {
            bytesFrame += (char) Integer.parseInt(hexFrame.substring(i*2, (i+1)*2), 16);
        }

        // This generates 2 TCP packets
        // outToServer.writeBytes(bytesFrame);
        // This generates only 1 TCP packet
        outToServer.write(bytesFrame.getBytes());

        // Read answer from server
        hexFrame = "";
        short frame_length = inFromServer.readShort();
        for (int i=0; i<frame_length; i++) {
            hexFrame += String.format("%2s", Integer.toHexString(inFromServer.readUnsignedByte())).replace(" ", "0");
        }

        System.out.println("Receive : " + hexFrame);

        socket.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

}

Java 和 TCP 都对此不作任何保证。 TCP 可以按照它喜欢的任何方式对数据进行分段,并且您无需依赖连续传送的任何两个字节。这里的问题确实是在阅读端,做出了错误的假设。

In fact, we communicate with binary frames

事实上,您是通过字节流协议进行通信的。没有框架,没有消息边界,什么都没有。

但是,如果你想对此进行更多控制,你应该在 DataOutputStream 和套接字输出流之间使用 BufferedOutputStream,在接收端同样使用 BufferedInputStream .当您希望发送数据时刷新流,通常是在下一次读取之前。