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

标签 java string sockets network-programming

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

玩家 1: 刚刚发送第 14 行第 11 列游戏结束 true

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

我很确定当我通过网络阅读时会发生错误。读取发生在它自己的线程中,BufferedReader 包裹在套接字的 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 方法非常简单(只是对包裹在套接字输出流的 DataOutputStream 进行写入),所以我认为问题不会发生在那里:

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

如有任何想法,我们将不胜感激。谢谢!

最佳答案

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

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

我重构了代码,为每条发送的消息添加换行符,然后简单地执行 readLine() 。这使得我的网络协议(protocol)能够依赖换行符作为消息分隔符,而不是 read() 方法。我很高兴地说这解决了问题。

感谢您的所有投入!

关于java - Java 网络程序中通过套接字发送的字符串中的最后几个字符有时会丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30141635/

相关文章:

string - 如何在 Redis 中进行搜索?

c# - 接收字节大小为 "dynamic"的套接字

java - 多客户端/服务器。处理通讯

java - 逻辑运算符优先级

java - Arial字体的跨平台解决方案

java - 使用openssl解密用java加密的aes-gcm

c++ - 如何在C++中将字符串转换为整数?

c# - Java 枚举与 C# 枚举 - 缺少的功能

python - 如何: From one string to another in a long list of strings

c++ - ESP32和Kotlin服务器之间的套接字延迟不一致