【问题标题】:Java8 BufferedReader.lines() stream hangs program compared to imperative solution与命令式解决方案相比,Java8 BufferedReader.lines() 流挂起程序
【发布时间】:2017-09-14 19:41:04
【问题描述】:

我目前正在用 ServerSocket 编写一个基本的网络服务器,并且我正在尝试使用 java 8 流来清理我的代码。这一直很好,但是当我尝试使用 BufferedReader 使用流读取请求时,我的程序挂起并且请求永远不会完全读入。我在下面列出了不同之处。

使用流:

InputStream stream = socket.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(stream));
System.out.println("----------REQUEST START---------");
List<String> rawRequest = in.lines()
    .peek(System.out::println)
    .map(line -> line.toString())
    .collect(Collectors.toList());
System.out.println("----------REQUEST END---------\n\n");

没有流:

 InputStream stream = socket.getInputStream();
 BufferedReader in = new BufferedReader(new InputStreamReader(stream));
 List<String> rawRequest = new ArrayList<>();
    try {

      System.out.println("----------REQUEST START---------");
      // read only headers
      for (String line = in.readLine(); line != null && line.trim().length() > 0; line = in.readLine()) {
        System.out.println(line);
        rawRequest.add(line);
      }
      System.out.println("----------REQUEST END---------\n\n");
    } catch (IOException e) {
      System.out.println("Error reading");
      System.exit(1);
    }

据我所知,除了错误处理之外,这些应该大致相同,除了在流中 sn-p System.out.println("----------REQUEST END---------\n\n"); 永远不会运行。

【问题讨论】:

  • 这是因为 lines() 永远不会返回,这是因为套接字仍然打开,因此阅读器在从行返回之前尝试读取更多数据(即,直到它到达 EOF) ()。
  • 您自己的评论“只读标题”宁可放弃游戏,您不觉得吗?
  • 顺便说一句,map(line -&gt; line.toString()) 绝对什么都不做。您正在将一个字符串...转换为一个字符串。

标签: java java-8 bufferedreader


【解决方案1】:

它们不是“大致等价的”。当读取空行时,您的“必要解决方案”将终止。另一个仅在流结束时终止,它不会到达,因为对等方保持连接打开以接收您的回复。

【讨论】:

  • 嗯,有道理,谢谢。有没有办法优雅地“强制”流返回?我的第一个想法是检查空白行并关闭缓冲的阅读器,但这显然不起作用,因为我需要将输出发送回用户;还是由于这种含义,命令式解决方案会更干净?
  • 在梳理完文档后,我找到了在不关闭套接字的情况下关闭输入流的正确方法(socket.shutdownInput())并让它正常工作
  • @Eric 否。您需要对 RFC 2616 和后续版本有很好的了解才能实现 HTTP,但这不是实现它的方法。传入请求的长度要么包含在 Content-length 标头中,要么包含在块的总和中。关闭输入违反了 HTTP keepalive。
  • @Eric Groom:Java 9 将允许插入 .takeWhile(line -&gt; !line.trim().isEmpty()),但正如 EJP 所说,您不应该尝试以这种方式实现 HTTP。您可以简单地使用URL 对象来建立连接;它仍然允许您流式传输实际内容……还有com.sun.net.httpserver.HttpServer 用于服务器端,即将成为 JDK9 标准的一部分,但它已经存在于 JDK8 中。
【解决方案2】:

你应该检查类似这样的空行和空行

in.lines()
.map(line -> line.trim())
.filter(line -> !line.isEmpty())
.map(line -> line.toString())
.collect(Collectors.toList());

这将跳过空行

【讨论】:

  • 他不想跳过空白行。他想在空白行终止
猜你喜欢
  • 1970-01-01
  • 2012-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-05
  • 2011-03-24
相关资源
最近更新 更多