【问题标题】:How to close a Java's socket's outputstream while keeping the inputstream open to get a result?如何在保持输入流打开以获得结果的同时关闭 Java 套接字输出流?
【发布时间】:2018-12-24 20:06:43
【问题描述】:

我正在向服务器发送消息,该消息正确传递。

但是,当我试图读取结果时,我得到一个异常 Socket is closed

知道如何关闭套接字的输出流,同时保持套接字和套接字的输入流打开以获得结果吗?

客户端代码:

Socket socket = new Socket("localhost", 9090);
String message = "Some message";
new OutputStreamWriter(socket.getOutputStream(), Charsets.UTF_8)
        .append(message)
        .close();
// The following line throws the exception when socket.getInputStream() is called:
String fromServer = CharStreams.toString(new InputStreamReader(socket.getInputStream(), Charsets.UTF_8));

例外:

java.net.SocketException: Socket is closed

    at java.net.Socket.getInputStream(Socket.java:903)
    at alik.server.test.Client.pingServer(Client.java:24)

【问题讨论】:

    标签: java sockets inputstream outputstream tcpsocket


    【解决方案1】:

    来自javadoc of Socket.getOutputStream()

    关闭返回的OutputStream 将关闭关联的套接字。

    换句话说,在完成输入流之前不要关闭输出流。关闭输入流也会关闭套接字(因此也会关闭输出流)。

    您可以使用Socket.shutdownOutput() 来防止进一步写入套接字,但我真的不明白使用它的意义,它可能导致对等方过早关闭其套接字,正如Stephen C 在 cmets 中解释的那样:

    对等方应该只有在读取时才能看到关闭的流。发生什么了 接下来将取决于它如何响应看到关闭的流。

    【讨论】:

    • 对等端应该只有在读取时才能看到关闭的流。接下来会发生什么将取决于它如何响应看到关闭的流。
    • @StephenC 谢谢,我不知何故模糊地回忆起某些套接字实现可能会提前关闭,但这可能只是记错了。我引用了您的评论作为解释。
    • 有可能......但是这样的实现会被破坏。只要我记得(即从 4.2bsd 开始),您就能够独立关闭套接字的输入和输出端。
    【解决方案2】:

    你不能在不关闭套接字的情况下关闭 OutputStream(参见下面的两个链接)。您需要这样做有什么具体原因吗?

    您需要在关闭套接字及其输入/输出流之前完成读/写。

    返回此套接字的输出流。

    如果此套接字具有关联的通道,则生成的输出流会将其所有操作委托给通道。如果通道处于非阻塞模式,则输出流的写操作将抛出 IllegalBlockingModeException。

    关闭返回的 OutputStream 将关闭关联的套接字。

    Behavior of Java sockets when closing output stream

    https://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#getOutputStream()

    【讨论】:

      【解决方案3】:

      正如 Joseph 所说,我认为您不应该在打开 InputStream 之前关闭 OutputStream。

      根据 Oracle Docs (https://docs.oracle.com/javase/tutorial/networking/sockets/readingWriting.html),正确的顺序是:

      1. 打开一个套接字。
      2. 打开套接字的输入流和输出流。
      3. 根据服务器的协议读取和写入流。
      4. 关闭流。
      5. 关闭套接字。

      【讨论】:

        【解决方案4】:

        要仅关闭输出流,请使用

        socket.shutdownOutput()
        

        docs

        【讨论】:

          【解决方案5】:

          你不能。关闭套接字输入或输出流会关闭另一个流和套接字。

          然而,这里真正的问题是,对等方在将任何内容发回之前试图读取直到流结束。这是一个应用程序协议问题。正如@MarkRotteveel 所提到的,您可以通过在发送所有要发送的内容后关闭用于输出的发送套接字来克服它,但这将您限制为每个连接一个请求/响应。

          最好查看您的应用程序协议以了解对等方如何知道请求的结束位置,并且在回复之前只阅读这么远的内容。例如,您可能应该发送线路。

          【讨论】:

            猜你喜欢
            • 2018-12-11
            • 1970-01-01
            • 2019-06-26
            • 2019-04-14
            • 2012-02-12
            • 1970-01-01
            • 2015-06-18
            • 1970-01-01
            • 2013-01-07
            相关资源
            最近更新 更多