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

时间:2017-07-05 10:28:29

标签: java tcp byte packet

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

实际上,我们使用二进制帧进行通信,因此所有帧必须以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();
    }

}

}

1 个答案:

答案 0 :(得分:0)

Java和TCP都不对此做出任何保证。 TCP可以按照自己喜欢的方式对数据进行分段,并且您无需依赖连续传输的任何两个字节。这里的问题实际上是在阅读结束时,这会产生错误的假设。

  

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

实际上,您正在通过字节流协议进行通信。没有帧,没有消息边界,没有。

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