为什么Java writeBytes方法在第一个TCP数据包中只发送一个字节,而write方法不发送?
我用java开发了一个简单的客户端(我使用Windows7机器)来与服务器通信。问题是服务器从未理解我的请求。因此,我分析了与Wireshark的通信,并注意到第一个TCP数据包中只发送一个字节,其余字节在另一个数据包中发送40毫秒后 事实上,我们使用二进制帧进行通信,因此所有帧必须以2字节的帧总长度开始。所以服务器永远不会理解我是正常的。我所有的帧都不会超过10字节,所以数据量微不足道。我知道TCP数据包是可以分割的,但对我来说,仅仅在一个字节后分割一个小帧是没有意义的 在数小时的研究不成功之后,我随意地尝试使用write方法而不是writeBytes方法以另一种方式发送字节。现在我只在一个TCP包中发送所有数据,通信工作正常,但我从未找到解释。如果有人知道,我会很高兴知道的 这是我的密码:为什么Java writeBytes方法在第一个TCP数据包中只发送一个字节,而write方法不发送?,java,tcp,byte,packet,Java,Tcp,Byte,Packet,我用java开发了一个简单的客户端(我使用Windows7机器)来与服务器通信。问题是服务器从未理解我的请求。因此,我分析了与Wireshark的通信,并注意到第一个TCP数据包中只发送一个字节,其余字节在另一个数据包中发送40毫秒后 事实上,我们使用二进制帧进行通信,因此所有帧必须以2字节的帧总长度开始。所以服务器永远不会理解我是正常的。我所有的帧都不会超过10字节,所以数据量微不足道。我知道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
的高位字节丢弃,因此它限制了您可以使用的字符集。好吧!这就是您的解释!