Java DataOutputStream 不写入所有消息(TCP 套接字)
Java DataOutputStream doesnt write all messages ( TCP Socket )
在我的客户端-服务器应用程序中,我发现了一个奇怪的错误。我得到以下方法:
sendLoginResponse();
sendPlayerList();
sendCurrentLevelState();
每个方法向客户端发送一个字节数组
如果我只调用其中的 2 个,一切正常,客户端获取所有发送的字节数组。但是,如果我调用所有 3 个方法,只有第一个和第二个方法到达客户端,则以下方法的顺序无关紧要。但服务器说所有这些都已发送。要使用
write(byte[] b, int off, int len);
方法
包中的所有长度也很有意义。
奇怪的地方来了:
如果我在第二个方法之后添加一个 Thread.sleep(1000);
,第三个方法现在会在休眠后到达客户端。我还尝试在每次写入调用后刷新 DataOutputStream,但这没有帮助。
编辑:
假设我发送 3 个登录响应
给我字节[]的方法:
public byte[] getLoginResponse(int playerID){
byte[] msg = new byte[4];
short shortMsgLength = 4;
byte[] msgLength = shortToBytes(shortMsgLength);
msg[0] = 2;
msg[1] = msgLength[0];
msg[2] = msgLength[1];
msg[3] = (byte) playerID;
return msg;
}
private byte[] shortToBytes(short value) {
byte[] returnByteArray = new byte[2];
returnByteArray[0] = (byte) (value & 0xff);
returnByteArray[1] = (byte) ((value >>> 8) & 0xff);
return returnByteArray;
}
以及发送方法:
private void sendLoginResponse() {
try{
byte[] msg = rfcObject.getLoginResponse(playerID);
out.write(msg,0,msg.length);
}catch(Exception e){
System.err.println(e.getMessage());
System.exit(0);
}
}
所以如果我连续调用 sendLoginResponse();
三次,客户端只收到 2 个字节数组,但服务器说它已经发送了 3 次。如果我添加
Thread.sleep(1000); `after the second Method-Call, everything works fine..`
读取消息的客户端在线程中运行:
public void run(){
while(true){
try {
byte[] data = new byte[MAX_DATA_SIZE]; // MAX_DATA = 255
byteCount = in.read(data);
} catch (IOException ex) {
handleExceptionError(ex);
}
}
}
谢谢!
DataOutputStream
并且 TCP 不会丢失数据。
正如在这种性质的问题中几乎无一例外地看到的那样,问题出在接收端。您可能假设 `read()' 填充了缓冲区,并忽略了它 returns.
的计数
根据您在评论中的协议描述,在这种情况下您应该使用DataInputStream.readFully()
:
byte type = din,readByte();
int length = din.readShort();
byte[] data = new byte[length];
din.readFully(data);
if I call the sendLoginResponse(); three times in a row, the client only recieves 2 byte-arrays, but the server says it has been sent 3 times.
这是因为TCP是面向流的协议。这意味着它不知道也不关心您的消息是如何定界的。 TCP 中没有单独消息的概念,只有字节流,并保证保留字节顺序。
所以当发送方调用三个write
时,这三个字节数组只是简单地通过连接连接起来并以相同的顺序到达接收方,但接收方不一定需要三个read
来获取所有字节,即使确实需要三个 read
,read
也不一定会给您相同的字节数组传递给每个相应的 write
.
您的消息已经具有从字节流中获取单个消息所需的信息:
// Client code for reading individual messages from a TCP connection
byte type = din.readByte();
// Read the message length, little-endian.
// We cannot use din.readShort because it's big-endian
int lenLo = din.read();
int lenHi = din.read();
short len = (short)(lenLo | (lenHi << 8));
byte [] body = new byte[len];
din.readFully(body);
在我的客户端-服务器应用程序中,我发现了一个奇怪的错误。我得到以下方法:
sendLoginResponse();
sendPlayerList();
sendCurrentLevelState();
每个方法向客户端发送一个字节数组
如果我只调用其中的 2 个,一切正常,客户端获取所有发送的字节数组。但是,如果我调用所有 3 个方法,只有第一个和第二个方法到达客户端,则以下方法的顺序无关紧要。但服务器说所有这些都已发送。要使用
write(byte[] b, int off, int len);
方法
包中的所有长度也很有意义。
奇怪的地方来了:
如果我在第二个方法之后添加一个 Thread.sleep(1000);
,第三个方法现在会在休眠后到达客户端。我还尝试在每次写入调用后刷新 DataOutputStream,但这没有帮助。
编辑:
假设我发送 3 个登录响应
给我字节[]的方法:
public byte[] getLoginResponse(int playerID){
byte[] msg = new byte[4];
short shortMsgLength = 4;
byte[] msgLength = shortToBytes(shortMsgLength);
msg[0] = 2;
msg[1] = msgLength[0];
msg[2] = msgLength[1];
msg[3] = (byte) playerID;
return msg;
}
private byte[] shortToBytes(short value) {
byte[] returnByteArray = new byte[2];
returnByteArray[0] = (byte) (value & 0xff);
returnByteArray[1] = (byte) ((value >>> 8) & 0xff);
return returnByteArray;
}
以及发送方法:
private void sendLoginResponse() {
try{
byte[] msg = rfcObject.getLoginResponse(playerID);
out.write(msg,0,msg.length);
}catch(Exception e){
System.err.println(e.getMessage());
System.exit(0);
}
}
所以如果我连续调用 sendLoginResponse();
三次,客户端只收到 2 个字节数组,但服务器说它已经发送了 3 次。如果我添加
Thread.sleep(1000); `after the second Method-Call, everything works fine..`
读取消息的客户端在线程中运行:
public void run(){
while(true){
try {
byte[] data = new byte[MAX_DATA_SIZE]; // MAX_DATA = 255
byteCount = in.read(data);
} catch (IOException ex) {
handleExceptionError(ex);
}
}
}
谢谢!
DataOutputStream
并且 TCP 不会丢失数据。
正如在这种性质的问题中几乎无一例外地看到的那样,问题出在接收端。您可能假设 `read()' 填充了缓冲区,并忽略了它 returns.
的计数根据您在评论中的协议描述,在这种情况下您应该使用DataInputStream.readFully()
:
byte type = din,readByte();
int length = din.readShort();
byte[] data = new byte[length];
din.readFully(data);
if I call the sendLoginResponse(); three times in a row, the client only recieves 2 byte-arrays, but the server says it has been sent 3 times.
这是因为TCP是面向流的协议。这意味着它不知道也不关心您的消息是如何定界的。 TCP 中没有单独消息的概念,只有字节流,并保证保留字节顺序。
所以当发送方调用三个write
时,这三个字节数组只是简单地通过连接连接起来并以相同的顺序到达接收方,但接收方不一定需要三个read
来获取所有字节,即使确实需要三个 read
,read
也不一定会给您相同的字节数组传递给每个相应的 write
.
您的消息已经具有从字节流中获取单个消息所需的信息:
// Client code for reading individual messages from a TCP connection
byte type = din.readByte();
// Read the message length, little-endian.
// We cannot use din.readShort because it's big-endian
int lenLo = din.read();
int lenHi = din.read();
short len = (short)(lenLo | (lenHi << 8));
byte [] body = new byte[len];
din.readFully(body);