通过套接字发送的字符串中的最后几个字符在Java网络程序中有时会丢失

通过套接字发送的字符串中的最后几个字符在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

现在,我正在尝试编写一个基于GUI的Java tic-tac-toe游戏,该游戏通过网络连接运行。它基本上在这一点上工作,但我有一个间歇性的错误,其中几个字符发送通过网络连接在游戏过程中丢失。有一个案例是这样的,当println语句被添加到message sends/reads时:

玩家1: 刚刚发送了第14行第11列GAMEOVER true

玩家2: 刚刚收到第14行第11列GAMEOV

我敢肯定,当我通过网络阅读时,错误就发生了。读取在其自己的线程中进行,并在套接字的InputStream周围缠绕一个BufferedReader,如下所示:

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();