InputStream 永远不会获取 EOF

InputStream never gets EOF

提问人:Tran 提问时间:9/14/2021 更新时间:9/14/2021 访问量:653

问:

首先,请允许我向您展示我的客户端代码:

                    String command;
                    socket.setSoTimeout(5000);
                    while(true) {
                        try {
                            final byte[] targetArray = new byte[is.available()];
                            final int x = is.read(targetArray);
                            if (x == -1) {
                                System.out.println("end");
                                break;
                            }
                            if (x == 0) continue;
                            command = new String(targetArray);
                            handleCommand(command).start();
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }

一旦连接到实际的套接字,客户端就会发送一些身份验证数据,但不会收到任何数据,现在,它会等待从服务器接收数据,当它这样做时,它会很好地处理它等,除了当我停止服务器时(从字面上关闭程序),什么也没发生,而实际上,我希望它发送 EOF (-1)。相反,它只是始终如一地发送垃圾邮件 0。

Java 套接字 inputstream eof

评论

1赞 that other guy 9/14/2021
当流到达末尾时,有 0 个字节可用,因此您一直尝试永远读取 0 个字节,该字节总是在读取 0 个字节后立即退出。您应该改用一些有用大小的缓冲区,例如 4096。
1赞 President James K. Polk 9/14/2021
它在文档中说:“如果 b 的长度为零,则不读取字节并返回 0;”
1赞 President James K. Polk 9/14/2021
此外,并非所有字符串字节编码的子序列都是有效的,因此对代码的假设是不正确的。此外,假设在对等体的一次操作中写入的确切字节将在您端的一次调用中读取,这是不正确的。此外,在编码/解码字符串时,请始终指定字符编码。

答:

4赞 gthanop 9/14/2021 #1

根据可用方法的文档(强调我的):

返回可读取的字节数的估计值...

使用此方法的返回值来分配旨在保存此流中所有数据的缓冲区是不正确的......

因此,根据您发布的最小代码,您不应该使用来分配缓冲区,因为它可能始终返回,这反过来又使操作始终返回 .但是根据您的问题,您只有在发送程序关闭时才会看到这种行为,这应该意味着:available0read0

  1. 该方法正确返回流中缓冲的字节数,因此这就是接收数据的原因。即使你消耗接收到的数据的速度比发送端发送的速度快(所以一些零可能会出现在 中),你也永远不会处理这种情况,这会在将来产生一些其他循环来捕获(最终)接收到的非零长度数据。availableavailablecontinue
  2. 一旦发送端关闭,就会有一个点,之后它总是会返回,因为它没有数据。因此,您分配零长度缓冲区,该方法首先检查缓冲区是否为零长度,而不是 EOF。0read

因此,请确保分配的缓冲区至少是 .1

此外,根据 Socket#getInputStream 方法的文档

如果套接字上没有缓冲字节,并且套接字尚未使用 关闭,则将返回 0。closeavailable