如何在保持输入流打开的同时关闭Java套接字的输出流?

时间:2018-07-17 07:51:54

标签: java sockets inputstream outputstream tcpsocket

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

但是,当尝试读取结果时,出现了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)

5 个答案:

答案 0 :(得分:8)

javadoc of Socket.getOutputStream()

  

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

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

您可以使用Socket.shutdownOutput()来防止对套接字的进一步写入,但是我真的看不到使用它的意义,并且可能导致对等节点过早关闭其套接字,如Stephen C在评论中解释:

  

对等方应该仅在读取后才看到关闭的流。怎么了   接下来将取决于它对看到封闭流的反应。

答案 1 :(得分: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()

答案 2 :(得分:1)

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

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

  
      
  1. 打开一个套接字。
  2.   
  3. 打开输入流并将输出流输出到套接字。
  4.   
  5. 根据服务器的协议读取和写入流。
  6.   
  7. 关闭流。
  8.   
  9. 关闭插座。
  10.   

答案 3 :(得分:0)

要仅关闭输出流,请使用

socket.shutdownOutput()

docs

答案 4 :(得分:-1)

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

但是,这里真正的问题是,对等方尝试读取直到流结束,然后再将任何内容发回。这是一个应用协议问题。如@MarkRotteveel所述,您可以在发送完所有要发送的内容后关闭发送输出的发送套接字,以解决此问题,但这将您限制为每个连接只有一个请求/响应。

最好查看您的应用协议,以发现对等方如何知道请求结束的位置,并且仅在回复之前阅读该信息。例如,可能您应该发送线路。