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

2022-01-19 00:00:00 sockets string network-programming java

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

Right now, I'm trying to write a GUI based Java tic-tac-toe game that functions over a network connection. It essentially works at this point, however I have an intermittent error in which several chars sent over the network connection are lost during gameplay. One case looked like this, when println statements were added to message sends/reads:

玩家 1:刚刚发送 ROW 14 COLUMN 11 GAMEOVER true

Player 1: Just sent ROW 14 COLUMN 11 GAMEOVER true

玩家 2:刚收到 ROW 14 COLUMN 11 GAMEOV

Player 2: Just received ROW 14 COLUMN 11 GAMEOV

当我通过网络阅读时,我很确定错误正在发生.读取发生在自己的线程中,BufferedReader 包裹在套接字的 InputStream 周围,如下所示:

Im pretty sure the error is happening when I read over the network. The read takes place in its own thread, with a BufferedReader wrapped around the socket's InputStream, and looks like this:

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 方法非常简单,(只是对包裹在套接字输出流周围的 DataOutputStream 进行写入)所以我认为问题不会发生在那里:

My sendMessage method is pretty simple, (just a write over a DataOutputStream wrapped around the socket's outputstream) so I don't think the problem is happening there:

try {
        dataOut.writeBytes(message);
        System.out.println("Just sent " + message);
    } 

任何想法将不胜感激.谢谢!

Any thoughts would be highly appreciated. Thanks!

推荐答案

事实证明,ready() 方法只保证下一次读取不会阻塞.因此, !ready() 不保证下一次读取将阻塞.只是它可以.

As it turns out, the ready() method guaruntees only that the next read WON'T block. Consequently, !ready() does not guaruntee that the next read WILL block. Just that it could.

我认为这里的问题与 TCP 堆栈本身有关.作为面向流的,当字节被写入套接字时,TCP 不保证它发送的字节的顺序或分组.我怀疑 TCP 堆栈正在以一种对它有意义的方式分解发送的字符串,并且在此过程中,ready() 方法必须检测到流中的某种潜在中断,并返回 false,尽管提供更多信息的事实.

I believe that the problem here had to do with the TCP stack itself. Being stream-oriented, when bytes were written to the socket, TCP makes no guarantees as to the order or grouping of the bytes it sends. I suspect that the TCP stack was breaking up the sent string in a way that made sense to it, and that in the process, the ready() method must detect some sort of underlying break in the stream, and return false, in spite of the fact that more information is available.

我重构了代码,为每个发送的消息添加了一个换行符,然后简单地执行了一个 readLine().这允许我的网络协议依赖换行符作为消息分隔符,而不是 ready() 方法.我很高兴地说这解决了问题.

I refactored the code to add a newline character to every message send, then simply performed a readLine() instead. This allowed my network protocol to be dependent on the newline character as a message delimiter, rather than the ready() method. I'm happy to say this fixed the problem.

感谢您的所有意见!

相关文章