这个问题已经 7 年了,但我有一个类似的问题,同时制作了一个 NIO 和 OIO 兼容的系统(客户端和服务器可能是他们想要的任何东西,OIO 或 NIO)。
由于阻塞 InputStreams,因此退出了挑战。
我找到了一种方法,使之成为可能,我想发布它,以帮助有类似问题的人。
在此处使用 DataInputStream 读取动态 sice 的字节数组,可以简单地将其包裹在 socketInputStream 周围。另外,我不想介绍特定的通信协议(比如首先发送字节大小,然后再发送),因为我想让它尽可能简单。首先,我有一个简单的实用程序 Buffer 类,如下所示:
import java.util.ArrayList;
import java.util.List;
public class Buffer {
private byte[] core;
private int capacity;
public Buffer(int size){
this.capacity = size;
clear();
}
public List<Byte> list() {
final List<Byte> result = new ArrayList<>();
for(byte b : core) {
result.add(b);
}
return result;
}
public void reallocate(int capacity) {
this.capacity = capacity;
}
public void teardown() {
this.core = null;
}
public void clear() {
core = new byte[capacity];
}
public byte[] array() {
return core;
}
}
这个类只存在,因为愚蠢的方式,字节 Java 中的字节自动装箱与这个列表一起工作。在这个例子中,这根本不需要,但我不想在这个解释中遗漏一些东西。
接下来,两个简单的核心方法。其中, StringBuilder 用作“回调”。它将填充已读取的结果并返回读取的字节数。当然,这可能会有所不同。
private int readNext(StringBuilder stringBuilder, Buffer buffer) throws IOException {
// Attempt to read up to the buffers size
int read = in.read(buffer.array());
// If EOF is reached (-1 read)
// we disconnect, because the
// other end disconnected.
if(read == -1) {
disconnect();
return -1;
}
// Add the read byte[] as
// a String to the stringBuilder.
stringBuilder.append(new String(buffer.array()).trim());
buffer.clear();
return read;
}
private Optional<String> readBlocking() throws IOException {
final Buffer buffer = new Buffer(256);
final StringBuilder stringBuilder = new StringBuilder();
// This call blocks. Therefor
// if we continue past this point
// we WILL have some sort of
// result. This might be -1, which
// means, EOF (disconnect.)
if(readNext(stringBuilder, buffer) == -1) {
return Optional.empty();
}
while(in.available() > 0) {
buffer.reallocate(in.available());
if(readNext(stringBuilder, buffer) == -1) {
return Optional.empty();
}
}
buffer.teardown();
return Optional.of(stringBuilder.toString());
}
第一个方法readNext 将使用来自DataInputStream 的byte[] 填充缓冲区并返回以这种方式读取的字节数。
在第二种方法readBlocking中,我利用了阻塞特性,不用担心consumer-producer-problems。只需readBlocking 将阻塞,直到收到新的字节数组。在我们调用这个阻塞方法之前,我们分配一个 Buffer-size。请注意,我在第一次读取后(在 while 循环内)调用了重新分配。这不是必需的。您可以安全地删除此行,代码仍然可以工作。我这样做了,因为我的问题的独特性。
我没有详细解释的两件事是:
1. 在(DataInputStream 和这里唯一的短变量,抱歉)
2. 断开连接(您的断开连接例程)
总而言之,您现在可以这样使用它了:
// The in has to be an attribute, or an parameter to the readBlocking method
DataInputStream in = new DataInputStream(socket.getInputStream());
final Optional<String> rawDataOptional = readBlocking();
rawDataOptional.ifPresent(string -> threadPool.execute(() -> handle(string)));
这将为您提供一种通过套接字(或任何 InputStream)读取任何形状或形式的字节数组的方法。希望这会有所帮助!