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

How to close a Java's socket's outputstream while keeping the inputstream open to get a result?

我正在向服务器发送一条消息,该消息正确通过。

但是,在尝试读取结果时,我得到一个异常 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)

您不能在不关闭套接字的情况下关闭 OutputStream(请参阅下面的两个链接)。您是否有特定原因需要这样做?

您需要完成 read/writing 才能关闭套接字,它是 input/output 流。

Returns an output stream for this socket.

If this socket has an associated channel then the resulting output stream delegates all of its operations to the channel. If the channel is in non-blocking mode then the output stream's write operations will throw an IllegalBlockingModeException.

Closing the returned OutputStream will close the associated socket.

Behavior of Java sockets when closing output stream

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

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

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

  1. Open a socket.
  2. Open an input stream and output stream to the socket.
  3. Read from and write to the stream according to the server's protocol.
  4. Close the streams.
  5. Close the socket.

来自 javadoc of Socket.getOutputStream()

Closing the returned OutputStream will close the associated socket.

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

您可以使用 Socket.shutdownOutput() to prevent further writing to the socket, but I don't really see the point of using that, and it could result in the peer closing its socket prematurely, as Stephen C 在评论中解释:

The peer should only see the closed stream if it reads. What happens next will depend on how it responds to seeing the closed stream.

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

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

最好查看您的应用程序协议,以发现对等方如何知道请求的结尾在哪里,并且在回复之前只读到那么远。例如,您可能应该发送线路。

要仅关闭输出流,请使用

socket.shutdownOutput()

docs