通过套接字发送的字符串中的最后几个字符在Java网络程序中有时会丢失
现在,我正在尝试编写一个基于GUI的Java tic-tac-toe游戏,该游戏通过网络连接运行。它基本上在这一点上工作,但我有一个间歇性的错误,其中几个字符发送通过网络连接在游戏过程中丢失。有一个案例是这样的,当println语句被添加到message sends/reads时: 玩家1: 刚刚发送了第14行第11列GAMEOVER true 玩家2: 刚刚收到第14行第11列GAMEOV 我敢肯定,当我通过网络阅读时,错误就发生了。读取在其自己的线程中进行,并在套接字的InputStream周围缠绕一个BufferedReader,如下所示:通过套接字发送的字符串中的最后几个字符在Java网络程序中有时会丢失,java,string,sockets,network-programming,Java,String,Sockets,Network Programming,现在,我正在尝试编写一个基于GUI的Java tic-tac-toe游戏,该游戏通过网络连接运行。它基本上在这一点上工作,但我有一个间歇性的错误,其中几个字符发送通过网络连接在游戏过程中丢失。有一个案例是这样的,当println语句被添加到message sends/reads时: 玩家1: 刚刚发送了第14行第11列GAMEOVER true 玩家2: 刚刚收到第14行第11列GAMEOV 我敢肯定,当我通过网络阅读时,错误就发生了。读取在其自己的线程中进行,并在套接字的InputStream
try {
int input;
while((input = dataIn.read()) != -1 ){
char msgChar = (char)input;
String message = msgChar + "";
while(dataIn.ready()){
msgChar = (char)dataIn.read();
message+= msgChar;
}
System.out.println("Just received " + message);
this.processMessage(message);
}
this.sock.close();
}
我的sendMessage方法非常简单(只需在围绕套接字的outputstream的DataOutputStream上进行写入),因此我认为问题不会发生在这里:
try {
dataOut.writeBytes(message);
System.out.println("Just sent " + message);
}
如有任何想法,将不胜感激。谢谢 尝试刷新发送方端的输出流。最后的字节可能保留在某些内部缓冲区中 尝试刷新发送方端的输出流。最后的字节可能保留在某些内部缓冲区中 事实证明,ready()方法只保证下一次读取不会阻塞。因此!ready()不能保证下一次读取将被阻止。只是它可以 我相信这里的问题与TCP堆栈本身有关。由于是面向流的,当字节写入套接字时,TCP不保证发送字节的顺序或分组。我怀疑TCP堆栈正在以一种对其有意义的方式分解发送的字符串,并且在这个过程中,ready()方法必须检测流中某种潜在的中断,并返回false,尽管有更多信息可用 我对代码进行了重构,在每次发送的消息中都添加了一个换行符,然后只执行了readLine()。这允许我的网络协议依赖于换行符作为消息分隔符,而不是ready()方法。我很高兴地说,这解决了问题 谢谢大家的意见 事实证明,ready()方法只保证下一次读取不会阻塞。因此!ready()不能保证下一次读取将被阻止。只是它可以 我相信这里的问题与TCP堆栈本身有关。由于是面向流的,当字节写入套接字时,TCP不保证发送字节的顺序或分组。我怀疑TCP堆栈正在以一种对其有意义的方式分解发送的字符串,并且在这个过程中,ready()方法必须检测流中某种潜在的中断,并返回false,尽管有更多信息可用 我对代码进行了重构,在每次发送的消息中都添加了一个换行符,然后只执行了readLine()。这允许我的网络协议依赖于换行符作为消息分隔符,而不是ready()方法。我很高兴地说,这解决了问题
谢谢大家的意见 使用何种类型的流化对象处理数据非常重要。在我看来,这个故障排除是由以下事实造成的:您使用DataOutputStream发送信息,而使用其他东西接收信息。尝试分别通过DataOutputStream和DataInputStream发送和接收信息 事实上,如果您通过调用dataOut.writebolean(b) 但是如果试图通过调用dataIn.readString()来接收这个消息,最终将一无所获DataInputStream和DataOutputStream是类型敏感的。试着重构你的代码,记住它 此外,一些输入流在调用read()单个字节时返回。在这里,您尝试将这一个字节转换为char,而在java中,char默认由两个字节组成
检查这是否是数据丢失的原因。使用何种类型的流对象来处理数据非常重要。在我看来,这个故障排除是由以下事实造成的:您使用DataOutputStream发送信息,而使用其他东西接收信息。尝试分别通过DataOutputStream和DataInputStream发送和接收信息 事实上,如果您通过调用dataOut.writebolean(b) 但是如果试图通过调用dataIn.readString()来接收这个消息,最终将一无所获DataInputStream和DataOutputStream是类型敏感的。试着重构你的代码,记住它 此外,一些输入流在调用read()单个字节时返回。在这里,您尝试将这一个字节转换为char,而在java中,char默认由两个字节组成
检查这是否是数据丢失的原因。是否有可能数据没有被其他线程完全刷新和接收?您是否验证了这一点?是否有可能其他线程没有完全刷新数据,也没有完全接收数据?您验证了吗?我刚刚尝试将dataOut.flush()添加到上述sendMessage方法中,刷新DataOutputStream。不幸的是,这似乎并没有缓解问题。添加这一行之后,我在运行程序时得到了以下输出:Player 1--刚刚发送了第24行第19列GAMEOVER false。玩家2--刚刚收到第24行第19列游戏结束。注意收到的消息中缺少的“false”…-我刚刚尝试将dataOut.flush()添加到上述sendMessage方法中,刷新DataOutputStream。不幸的是,这似乎并没有缓解问题。添加这一行之后,我在运行程序时得到了以下输出:Player 1--刚刚发送了第24行第19列GAMEOVER false。玩家2--刚刚收到第24行第19列GAM
msgChar = (char)dataIn.read();