【问题标题】:Proper way of closing Streams in Java Sockets在 Java 套接字中关闭流的正确方法
【发布时间】:2013-07-11 04:12:26
【问题描述】:

我看到了一些关于这个的帖子,但我仍然找不到答案。

这是我的服务器与客户端交互的方式:

public void run () {
    try {
        //Read client request
        InputStream is = server.getInputStream();
        byte[] buff = new byte[1024];
        int i;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((i = is.read(buff, 0, buff.length)) != -1) {
            bos.write(buff, 0, i);
            System.out.println(i + " bytes readed ("+bos.size()+")");
        }
        is.close();
        is = null;
        //Do something with client request

        //write response
        OutputStream os = server.getOutputStream();
        os.write("server response".getBytes());
        os.flush();
        os.close();
        os = null;

    } catch (IOException ioe) {
        ioe.printStackTrace();
    }
}

这是客户端:

public void run() {
        try {
            InetAddress serverAddr = null;
            serverAddr = InetAddress.getByName("10.0.2.2");
            socket = new Socket(serverAddr, 5000);

            //Send Request to the server
            OutputStream os = socket.getOutputStream();
            os.write(jsonRequest.toString().getBytes("UTF-8"));
            os.flush();
            os.close();
            os = null;

            //Read Server Response
            InputStream is = socket.getInputStream();
            byte[] buff = new byte[1024];
            int i;
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            while ((i = is.read(buff, 0, buff.length)) != -1) {
                bos.write(buff, 0, i);
                System.out.println(i + " bytes readed ("+bos.size()+")");
            }
            is.close();
            is = null;

            //Do something with server response

        } catch (UnknownHostException uhe) {
            sendCallbackError(uhe);
        } catch (IOException ioe) {
            sendCallbackError(ioe);
        }
    }

如您所见,客户端连接并发送请求。服务器读取该请求,然后写入客户端将读取的响应。

此代码的问题在于客户端中的OutputStream.close() 和服务器中的InputStream.close()。如 Javadocs 中所述,关闭流将关闭 Socket。结果是当客户端尝试读取服务器响应时,Socket 已经关闭。

我已经设法通过调用Socket.shutdownInputSocket.shutdownOutput 来克服这个问题。但是我仍在思考这是否是正确的做法

请注意,当服务器写入响应或客户端读取响应时,使用close() 关闭流不会产生问题(我猜想关闭在客户端和服务器之间是同步的)。

所以我的问题是:

  1. 使用 Socket 关闭方法是否正确?
  2. 我可以用close() 继续关闭最后一个流吗(发送和阅读时 来自服务器的响应)
  3. 关闭时关闭是否会保留一些数据? 缓冲区并且不会被发送?

【问题讨论】:

  • 将 socket.close() 放入 finally 块中。
  • @PeterLawrey 你的意思是不关闭流并关闭套接字吗?如果是的话,我想我应该关闭两端的套接字,对吧?
  • 你应该关闭套接字,如果你想先刷新输出流,你可能想先关闭或刷新它。
  • @PeterLawrey 我很困惑。 Javadocs 清楚地表明(这段代码证明了这一点),当 Stream 关​​闭时,Socket 也关闭了。你的意思是像下面诺顿所说的:在 finally 块中关闭流然后关闭套接字?
  • 如果你有一个 BufferedOuptutStream 并且它有未发送的数据(在缓冲区中)你只需要关闭流如果不是这种情况,你只需要关闭套接字。如果关闭套接字并且有未发送的数据,则永远不会发送。

标签: java android sockets inputstream


【解决方案1】:

您可以执行以下操作:

try{
}catch(){
}finally{
if(is!=null){
is.close();
}
if(os!=null){
os.close();
}
}

【讨论】:

  • 这是一个简化的例子。 Streams 实际上是在从 run() 方法调用的不同方法中创建的。所以我真的无法访问这些变量,除非我将它们声明为 Runnable 类的成员变量
  • 尝试了您的建议。这对我不起作用,因为如果客户端的 OutputStream 没有关闭/关闭,服务器会一直读取。也许我应该发送一个终止序列来完成阅读......
【解决方案2】:

此代码的问题在于客户端中的 OutputStream.close() 和服务器中的 InputStream.close()。如 Javadocs 中所述,关闭流将关闭 Socket。

正确,但服务器中的InputStream 没有直接连接到Socket:,它连接到你不知道的东西。您可以不受惩罚地关闭它,尽管您根本不需要关闭它。如果您愿意,您可以关闭服务器中的 OutputStream:不过,同样,由于它没有直接连接到 Socket,,它可能有也可能没有除刷新之外的任何影响。

要解决您的实际问题,您无需关闭客户端中的输出流,但您需要发送适当的 Content-Length: 标头。这样服务器就知道要从客户端读取多少。如果这只是一个 GET 请求,则内容长度很可能为零。你不需要打电话给shutdownOutput(),,虽然我想没有什么可以阻止你,而且打电话给shutdownInput()对网络没有任何影响,所以再次没有任何意义。

【讨论】:

  • 虽然您对服务器中的 InputStream 可能是正确的,但如果我关闭它然后尝试打开 OutputStream,它将失败并出现 Socket Closed IOException。关于 Content-Length,我理解您的意思是保留字节数组的第一个字节来指定消息长度,对吗?我认为这应该是最好的解决方案,因为除非我关闭()服务器中的 OutputStream 或调用 socket.shutdownOutput(),否则我在服务器中中断读取的方式(read()!= -1)不会被触发。最新的工作正常。
  • (1) 所以不要关闭它。关闭与否与您的问题无关。 (2) 不,我指的是 HTTP Content-Length 标头。查一下。
  • 这是一个普通的套接字连接,以普通的旧字节发送 JSON,这是唯一实现的协议。我不知道 HTTP 标头如何适合此实现...
猜你喜欢
  • 2010-10-13
  • 1970-01-01
  • 2016-05-12
  • 1970-01-01
  • 1970-01-01
  • 2018-05-17
  • 2023-01-17
  • 2012-02-10
  • 2012-08-02
相关资源
最近更新 更多