【问题标题】:Java nio read() return -1Java nio read() 返回 -1
【发布时间】:2013-01-04 08:16:49
【问题描述】:

这不是我第一次尝试理解这个问题,但我希望这将是最后一个:

一些背景:

我有一个Java SocketChannel NIO 服务器在非阻塞模式下工作。

此服务器有多个客户端,它们从它发送和接收消息。

每个客户端每隔一段时间就会使用"keepalive" 消息保持与服务器的连接。 服务器的主要思想是客户端将“始终”保持连接并以“推送”模式接收来自它的消息。

现在回答我的问题:

在 Java NIO read() 函数中 - 当 read() 返回 -1 - 这意味着它的 EOS。

在我问过here 的问题中,我意识到这意味着套接字已完成其当前流并且不需要关闭..

在 google 中搜索更多关于此的内容时,我发现这确实意味着连接在另一端关闭..

  1. “流”这个词到底是什么意思?它是从客户端发送的当前消息吗?客户端连接是否能够发送更多消息?

  2. 如果客户从未告诉他关闭SocketChannel,为什么要在客户端关闭?

  3. read() return -1 和对等 I/O 错误重置连接有什么区别?

这就是我从SocketChannel阅读的方式:

private JSONObject readIncomingData(SocketChannel socketChannel)
        throws JSONException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException {
    JSONObject returnObject = null;
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    Charset charset = Charset.forName("UTF-8");
    String endOfMesesage = "\"}";
    String message = "";
    StringBuilder input = new StringBuilder();      
    boolean continueReading = true;
    while (continueReading && socketChannel.isOpen()) 
    {
        buffer.clear();         
        int bytesRead = socketChannel.read(buffer);             
        if (bytesRead == -1)
        {
            continueReading = false;                    
            continue;
        }
        buffer.flip();
        input.append(charset.decode(buffer));
        message = input.toString();
        if (message.contains(endOfMesesage))
            continueReading = false;
    }       
    if (input.length() > 0 && message.contains(endOfMesesage))
    {
        JSONObject messageJson = new JSONObject(input.toString());
        returnObject = new JSONObject(encrypter.decrypt(messageJson.getString("m")));
    }           
    return returnObject;
}

【问题讨论】:

    标签: java nio socketchannel


    【解决方案1】:

    “流”这个词究竟是什么意思?它是从客户端发送的当前消息吗?客户端连接是否能够发送更多消息?

    流表示在两个位置之间流动的数据,通常在客户端和服务器之间,但实际上它是任何类型的数据流动。例如。如果您从硬盘读取文件,则使用 FileInputStream 表示从磁盘上的文件流向程序的数据。这是一个非常笼统的概念。把它想象成一条河流,水就是数据。此外,它是一种非常酷的河流,可让您控制水/数据的流动方式。

    如果客户端从未告诉他关闭,为什么还要在客户端关闭 SocketChannel?

    如果客户端和服务器之间的连接被重置或中断,就会发生这种情况。你的程序永远不应该假设连接只是存在并且永远不会中断。连接因各种原因而中断,可能是网络组件不稳定,有人拔掉了最好留在原处的插头,或者无线网络出现故障。服务器也可能关闭连接,例如如果服务器程序出现故障、出现错误或连接超时。永远记住,打开的连接是有限的资源,因此如果它们空闲太久,服务器可能会决定关闭它们。

    read() return -1 和 peer I/O error 重置连接有什么区别?

    当 read() 返回 -1 时,这仅意味着流中当前没有更多数据。连接重置意味着,可能有更多数据,但连接不再存在,因此无法再读取此数据。再次采用河流类比:将数据想象为使用连接两个村庄的河床(连接)从上游村庄(又名 Serverville)向下游村庄(又名 Clientville)输送一定量的水。现在,Serverville 的某个人拉动大杠杆,水(数据)从 Serverville 流向 Clientville。在 Serverville 发送了它想要发送的所有水之后,它关闭了控制杆,河床将再次变空(实际上随着连接关闭而被破坏)。这就是 Clientville 获得 -1 的地方。现在想象一下,一些推土机打断了河床,一些水永远不会流到 Clientville。这就是“连接重置”的情况。

    希望这会有所帮助:)

    【讨论】:

    • 它确实有很大帮助!但是-如果我得到- 1-在河流类比中的水-这是否意味着这条河将永远不再有水了?还是只是当前的水流结束了?
    • 1 / 3。(2)和(3)都不正确。除非客户端明确“这么说”,即关闭或退出,否则无法在客户端关闭连接。 “对等方重置连接”根本不表示“可能有更多数据”,这是一个协议错误,纯粹而简单,在这一点上,你继续用河流进行类比是完全不正确的。投反对票。
    • 嗯,是的,这条河再也不会有水了(这就是类比落空的地方)。如果您正在重用连接但当前没有可用数据,则 read 将返回 0(即读取了 0 个字节)。
    • @EJP 我承认这个类比(就像每个类比一样)有些缺陷,但它有助于理解这一点,这是使用类比的目的。当然,我本可以引用 TCP 规范并谈论协议错误,但我怀疑这对发帖人有多大帮助。但是您也添加了您的答案,这在形式上更正确,因此张贴者现在可以充分利用这两个答案。这就是我喜欢这个网站的原因:)
    • 我一般不介意类比,即使是精度有限的类比,但你的类比确实具有误导性。 “由于在某个时候只有有限数量的数据,河床将再次空无一人。这就是 Clientville 得到 -1 的地方。只是 false。 它与“数据量有限”或“空河床”无关。它与 错误条件有关。
    【解决方案2】:

    “流”这个词到底是什么意思?它是从客户端发送的当前消息吗?

    它是字节流,而不是消息。您可以使用这些字节来形成一条消息,但流不知道您正在这样做,它也不以任何方式支持消息。

    如果客户端从未告诉他关闭,为什么还要在客户端关闭 SocketChannel?

    如果另一端关闭它,它只能用 -1 关闭。

    read() return -1 和 peer I/O error 重置连接有什么区别?

    您可以通过其他方式关闭或断开连接,例如从同一侧关闭连接,或连接超时,例如拔出网线。

    顺便说一句:您编写代码的方式更适合阻止 NIO。例如,如果您收到多条完整消息,则第一条消息之后的任何内容都将被丢弃。如果您使用阻塞 IO 并保留您阅读的所有内容,您将不会收到损坏或丢失的消息。

    【讨论】:

    • 好的,但是拔出网线会返回-1还是发送连接由对等错误重置?你有重新编码的建议吗?为了避免丢失消息,客户端一次只发送一条消息
    • 超时后拔出线缆会导致异常。我建议重新编码,这样您就可以保留您阅读的所有数据,而不仅仅是您期望的数据。 read() 将为您提供 1 字节和缓冲区的最大大小之间的值。一次只发送一条消息并不意味着一次只会收到一条消息,也不保证第一个 read() 将是一条完整的消息。
    【解决方案3】:
    1. “流”这个词究竟是什么意思?是客户端发送的当前消息吗?

    它基本上意味着连接的一侧,即全双工。 TCP 是一种字节流协议,提供两个独立的字节流,每个方向一个。

    1. 如果客户端从未告诉他关闭,为什么还要在客户端关闭 SocketChannel?

    不会的。客户端确实关闭了连接。这就是 read() 返回 -1 的含义。

    read() return -1 和 peer I/O error 重置连接有什么区别?

    read() 返回 -1 表示对端正确关闭了连接。 'Connection reset by peer' 表示某种协议错误,通常是您将数据写入已被对等方关闭的连接。

    你的代码,如果read()返回-1你必须关闭通道。没有其他明智的方法可以继续。

    【讨论】:

    • 好的,这很有帮助。常规套接字 readLine() 方法呢?当它返回 null 时 - 它与 read() == -1 相同吗?
    猜你喜欢
    • 2012-12-11
    • 1970-01-01
    • 2020-04-29
    • 2011-01-13
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    • 1970-01-01
    相关资源
    最近更新 更多