3

我有以下从缓冲阅读器读取的示例:

while ((inputLine = input.readLine()) != null) {
   System.out.println("I got a message from a client: " + inputLine);
}

只要缓冲阅读器中出现某些内容(在本例中),println就会执行循环中的代码。input就我而言,如果客户端应用程序向套接字写入内容,则循环中的代码(在服务器应用程序中)将被执行。

但我不明白它是如何工作的。inputLine = input.readLine()等待直到缓冲阅读器中出现某些内容,当那里出现某些内容时,它返回true并执行循环中的代码。但是什么时候null可以退。

还有一个问题。上面的代码取自一个方法,throws Exception我在 Thread 的 run 方法中使用了这个代码。而当我试图在编译器抱怨throws Exception之前放run:被覆盖的方法不会抛出异常。如果没有throws exception编译器,我还有另一个抱怨:​​未报告的异常。那么,我能做些什么呢?

4

9 回答 9

5

当另一端的套接字关闭时,阅读器应该返回一个空字符串。这是您正在寻找的条件。要处理异常,请将读取循环包装在 try/catch 块中。

 try {
   while ((inputLine = input.readLine()) != null) {
     System.out.println("I got a message from a client: " + inputLine);
   }
 }
 catch (IOException e) {
   System.err.println("Error: " + e);
 }

您可能会发现本教程关于在 Java 中读取/写入套接字,很有帮助。

于 2010-03-23T13:20:40.290 回答
3

对于你的第一个问题:

但我不明白它是如何工作的。inputLine = input.readLine() 一直等到缓冲阅读器中出现某些内容,当那里出现某些内容时,它返回 true 并执行循环中的代码。但是什么时候可以返回null。

BufferedReader.readLine() 成功后不返回true。它返回一个包含已读取行的字符串。如果到达流的末尾,则返回null.

你的第二个问题:

上面的代码取自一个抛出异常的方法,我在线程的运行方法中使用了这段代码。当我尝试在运行之前抛出异常时,编译器会抱怨:被覆盖的方法不会抛出异常。如果没有 throws 异常,我还有编译器的另一个抱怨:​​未报告的异常。那么,我能做些什么呢?

您应该将代码包装在try/catch 块中。如果您不想处理捕获的异常,只需将该部分留空(不推荐)

try {
    while ((inputLine = input.readLine()) != null) {
        System.out.println("I got a message from a client: " + inputLine);
    }
} catch (Exception e) {
    //handle exception
}
于 2010-03-23T13:30:39.733 回答
1

阅读器的 readLine() 将在读取内容时返回一个字符串值,在还没有任何内容时返回一个空字符串,当连接关闭时返回 null。

我建议使用 IO 函数将 try/catch 包裹在您的代码块周围,并适当地处理错误。

于 2010-03-23T13:21:43.150 回答
0

inputreader 连接到套接字,它是一个侦听器,即不断侦听传入的消息。

关于您的第二个问题,您应该在方法中放置一个 try/catch 块,捕获异常并处理它。不要重新扔。

于 2010-03-23T13:18:48.750 回答
0

但我不明白它是如何工作的。.... 等到缓冲阅读器中出现某些内容,当那里出现某些内容时,它返回 true

不,它返回表达式 (inputLine = input.readLine()) 的值,即 inputLine 本身。inputLine 与 null 进行比较。

于 2010-03-23T13:22:01.310 回答
0

到达“EOF(文件结尾)”时返回 null。由于这是从网络套接字读取的,因此当套接字断开连接(由服务器或客户端)时会创建文件结尾,但您可能会在实际看到 EOF 之前得到一个异常。

于 2010-03-23T13:22:55.213 回答
0

如果这不是家庭作业,您可能需要查看 Apache Commons IOUtils

假设您不创建 BufferedReader,而只是停在 InputStream:

String results = IOUtils.toString(inputStream);
System.out.println(results);
于 2010-03-23T13:24:58.610 回答
0
while ((inputLine = input.readLine()) != null) {

查看表达式的每个部分:

input.readLine()

如果已到达流的末尾(或在错误时抛出异常),则返回一个字符串,该字符串将为空。

inputLine = input.readLine()

将此字符串分配给 inputLine

((inputLine = input.readLine()) != null)

检查分配的字符串不为空(流结束)。

于 2010-03-23T13:27:47.740 回答
0

你已经收到了一些很好的答案。只需捕获异常并在本地处理即可。如果您需要将此传递给其他代码但由于该run()方法不允许任何检查异常而不能,您可以将异常包装在某种 RuntimeException 中。如果 run 方法直接在 Thread 上执行(因为它可能是 Runnable),那么您应该注意重新抛出包装的异常。

至于 的结果readLine(),它会null在没有更多内容可读取时返回。在套接字的情况下,这是当另一端干净地关闭套接字时(任何突然终止或不干净的关闭通常会导致代码中的异常,因为操作系统将发送不同类型的套接字关闭通知)。

我确实有一个警告,因为您将套接字包装在java.io.BufferedReader. 在任何类型的生产代码中使用它时都应该非常小心。

危险在于 BufferedReader 不能很好地处理读取过程中的异常。如果您在套接字上启用了超时,这尤其是一个问题,因此代码将自动从操作系统接收定期异常。读取器内的缓冲区正在填充时,可能会出现超时(或其他异常)。如果您尝试在异常后重用该对象,它将忽略缓冲区中任何先前的内容。先前收到的数据包会默默丢失,并且无法检索这些字节。

请注意,还有其他类型的套接字异常并不意味着套接字已丢失。例如,查看 的定义java.io.InterruptedIOException。这有一个公共变量报告在最近的 I/O(读或写)请求中成功传输的字节数。这意味着可以再次执行 IO 操作以检索或发送数据包的剩余字节。

如果出现任何异常,您的设计是立即关闭阅读器和套接字,该方法将正常工作。

从套接字读取的正确方法是直接使用套接字流,使用 NIO(ByteBuffers 等),或者使用编写良好的网络库,对这些较低级别的类进行良好的抽象(有几个开源类可用)。

于 2010-03-23T15:36:07.483 回答