【问题标题】:InputStream can't handle 2016 bytesInputStream 无法处理 2016 字节
【发布时间】:2020-03-16 20:25:56
【问题描述】:

我最近用 Java 编写了一个程序,它可以自动创建加密连接并传输有关它们的数据。现在我遇到的问题是,如果一次传输大量数据,输入流不再反应。 (我尝试一次传输 2016 个字节)

但我认为问题在于低字节传输。

服务器:

    public byte[] read() throws IOException {
        byte[] bytes = new byte[2];
        this.inputStream.read(bytes);
        int length = ((bytes[0] & 0xff) << 8) | (bytes[1] & 0xff);
        byte[] buffer = new byte[length];
        this.inputStream.read(buffer);
        return this.encryption.decryptAES(buffer);
    }

客户:

    public void write(byte[] message) throws IOException {
        byte[] bytes = new byte[2];
        message = this.encryption.encryptAES(message);
        bytes[1] = (byte) (message.length & 0xFF);
        bytes[0] = (byte) ((message.length >> 8) & 0xFF);
        this.outputStream.write(bytes);
        this.outputStream.write(message);
    }

InputStreams 没有关闭或为空。 也没有抛出异常。

程序在读取服务器端字节数组长度的字节时挂起。在客户端,字节已成功发送。

【问题讨论】:

  • read() 没有义务填充缓冲区,并且您忽略了它可能没有或确实可能已到达流末尾的两种情况。使用DataInputStream.readFully(),当您使用它时,使用它的readShort() 方法,并在发件人处使用DataOutputStream.writeShort()

标签: java arrays encryption stream byte


【解决方案1】:

read 调用按设计工作;您只是对它的设计方式感到困惑(这确实有点奇怪)。

read(byteArray)方法保证至少读取1个字节;如果发生异常或关闭流,它只会读取 none。

但是,不能保证填充提供的字节数组。它只读取 1 个字节就很好(规范说这没问题,因此,必须编写代码来处理它)。即使还有更多要发送。

那么,你实际上最终得到了多少字节? ¯_(ツ)_/¯ 取决于你的网卡、操作系统、虚拟机和月相。

因此,像这样的“单独”读取调用始终是一个错误。它必须发生在某种循环中。

幸运的是,除非您使用的是相当旧的 java 版本,否则您不必编写任何程序;如今,InputStream 类型具有 readNBytes 方法,这将保证它将填充整个提供的字节数组,只有在发生异常或流在填充完整字节数组之前结束时才给你更少的字节。

因此,正确的调用是in.readNBytes(buffer, 0, buffer.length),而不是:in.read(buffer)

注意:read 的设计是这样的,因为它与 I/O 的实际工作方式相吻合:我现在可以给你 2016 字节;如果您想要更多,则需要更长的时间(再次往返卡,或者可能等待 IP 数据包穿越海洋,谁知道这可能需要多长时间);并且通常您实际上不可能知道创建字节数组的神奇大小,以便您获得尽可能快的响应,而不会向read() 发出大量请求,这也会很慢——因此,您无法解决这种困境的说法是:“好吧,如果你想要快速响应,只需给出一个小字节数组!”。现在你知道为什么它是这样设计的了:)

【讨论】:

  • 但是我怎么知道我的数组的长度是多少?
  • 我们怎么知道?首先阅读例如将 32 位转换成一个整数,然后询问以该整数编码的大小(即前缀长度)。
  • @Paul 从您的代码中,看起来您已经知道:您正在阅读长度。只需将 .read(b) 调用替换为 .readNBytes(b, 0, b.length) 并重新运行测试。
  • @Paul 如果您采用此路径,请确保在读取长度字的字节时也使用它。
  • @rzwitserloot 好吧,我把它改成了readNBytes,但它在读取字节长度时一直挂断。我认为问题在于拆分整数或类似的东西
猜你喜欢
  • 1970-01-01
  • 2011-12-13
  • 2011-05-17
  • 2019-11-05
  • 2012-11-30
  • 2021-01-23
  • 2014-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多