InputStream 无法处理 2016 字节
InputStream can't handle 2016 bytes
我最近在 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
调用按设计工作;您只是对它的设计方式感到困惑(这确实有点奇怪)。
read(byteArray)
方法保证至少读取1个字节;如果发生异常或流关闭,它只会读取 none。
但是,不能保证填充提供的字节数组。它只读取 1 个字节是完全没问题的(规范说这是可以的,因此,必须编写您的代码来处理它)。就算有再发。
那么,您实际上最终得到了多少字节? ¯_(ツ)_/¯ 取决于网卡、OS、VM、月相
因此,像这样的 'lone' 读取调用始终是一个错误。它必须发生在某种循环中。
幸运的是,除非您使用的是相当旧的 java 版本,否则您不必编写任何程序;现在 InputStream
类型有 readNBytes
方法,这将保证它将填充整个提供的字节数组,只有在发生异常或流在完整字节数组之前结束时才会给你更少的字节已满
所以,而不是:in.read(buffer)
,正确的调用是 in.readNBytes(buffer, 0, buffer.length)
。
注意:read
的设计是这样的,因为它与 I/O 的实际工作方式相吻合:我现在可以给你 2016 个字节;如果您想要更多,则需要更长的时间(到卡的另一次往返,或者可能等待 IP 数据包穿越海洋,谁知道这可能需要多长时间);通常你不可能真正知道制作字节数组的神奇大小,这样你就可以获得尽可能快的响应,而无需向 read()
发出大量请求,这也会很慢 - 因此,你可以'不要通过说:"Well, just give a small byte array if you want fast responses!" 来解决这个难题。现在你知道为什么要这样设计了吧:)
我最近在 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
调用按设计工作;您只是对它的设计方式感到困惑(这确实有点奇怪)。
read(byteArray)
方法保证至少读取1个字节;如果发生异常或流关闭,它只会读取 none。
但是,不能保证填充提供的字节数组。它只读取 1 个字节是完全没问题的(规范说这是可以的,因此,必须编写您的代码来处理它)。就算有再发。
那么,您实际上最终得到了多少字节? ¯_(ツ)_/¯ 取决于网卡、OS、VM、月相
因此,像这样的 'lone' 读取调用始终是一个错误。它必须发生在某种循环中。
幸运的是,除非您使用的是相当旧的 java 版本,否则您不必编写任何程序;现在 InputStream
类型有 readNBytes
方法,这将保证它将填充整个提供的字节数组,只有在发生异常或流在完整字节数组之前结束时才会给你更少的字节已满
所以,而不是:in.read(buffer)
,正确的调用是 in.readNBytes(buffer, 0, buffer.length)
。
注意:read
的设计是这样的,因为它与 I/O 的实际工作方式相吻合:我现在可以给你 2016 个字节;如果您想要更多,则需要更长的时间(到卡的另一次往返,或者可能等待 IP 数据包穿越海洋,谁知道这可能需要多长时间);通常你不可能真正知道制作字节数组的神奇大小,这样你就可以获得尽可能快的响应,而无需向 read()
发出大量请求,这也会很慢 - 因此,你可以'不要通过说:"Well, just give a small byte array if you want fast responses!" 来解决这个难题。现在你知道为什么要这样设计了吧:)