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

为什么Java writeBytes方法在第一个TCP数据包中只发送一个字节,而write方法不发送?,java,tcp,byte,packet,Java,Tcp,Byte,Packet,我用java开发了一个简单的客户端(我使用Windows7机器)来与服务器通信。问题是服务器从未理解我的请求。因此,我分析了与Wireshark的通信,并注意到第一个TCP数据包中只发送一个字节,其余字节在另一个数据包中发送40毫秒后 事实上,我们使用二进制帧进行通信,因此所有帧必须以2字节的帧总长度开始。所以服务器永远不会理解我是正常的。我所有的帧都不会超过10字节,所以数据量微不足道。我知道TCP数据包是可以分割的,但对我来说,仅仅在一个字节后分割一个小帧是没有意义的 在数小时的研究不成功之

我用java开发了一个简单的客户端(我使用Windows7机器)来与服务器通信。问题是服务器从未理解我的请求。因此,我分析了与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();
    }

}
import java.io.DataInputStream;
导入java.io.DataOutputStream;
导入java.io.IOException;
导入java.net.InetSocketAddress;
导入java.net.Socket;
公共类客户端{
公共静态void main(字符串argv[]){
试一试{
套接字=新套接字();
socket.connect(新的InetSocketAddress(“10.2.1.1”,1003),1000);
DataOutputStream outToServer=新的DataOutputStream(socket.getOutputStream());
DataInputStream INFOROMSERVER=新的DataInputStream(socket.getInputStream());
//要发送到服务器的十六进制帧
字符串hexFrame=“0004FF9D3175”;
//构建字节帧
字符串字节帧=”;

对于(int i=0;iJava和TCP对此都不做任何保证。TCP可以按自己喜欢的方式对数据进行分段,并且您不必依赖于连续交付的任何两个字节。这里的问题实际上是在读取端,这导致了错误的假设

事实上,我们用二进制帧进行通信

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


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

谢谢对于您的回答,您是对的,使用缓冲流并在下次读取之前刷新它会使代码更强大,因此我应用了这些修改。但出于好奇,我尝试发送带有终止字符“Hello\n”的ascii帧,例如,并用java编写基本服务器。writeBytes方法始终发送第一个字节(“H”)在一个单独的TCP数据包中,而write方法从不这样做。我不在乎数据包是否被分段并在服务器上重新组装,以便只看到一个帧。但事实并非如此,我的实际服务器使用writeBytes方法看到两个分离的帧。这样做是因为底层流没有缓冲。
writeBytes()
实际上一次从字符串中写入一个字节。TCP将立即发送第一个字节,但随后进入Nagle模式,并在飞行中有未确认的数据时开始缓冲。如果添加
BufferedOutputStream
并按指示刷新,则不会发生。
writeBytes()
可能是因为另一个原因而使用的错误API:它只是将每个
char
的高位字节丢弃,因此它限制了您可以使用的字符集。好吧!这就是您的解释!