1 回答
TA贡献1883条经验 获得超3个赞
如果您没有调用configureBlocking(false)
,那么是的,您将使用循环来填充缓冲区。
然而……非阻塞套接字的要点是不要挂起等待任何一个套接字,因为这会延迟从所有剩余套接字(其选定的键尚未被迭代器处理)的读取。实际上,如果十个客户端连接,并且其中一个碰巧连接速度较慢,则其他部分或全部客户端可能会遇到同样的缓慢情况。
(未指定所选键集的确切顺序。查看 Selector 实现类的源代码是不明智的,因为缺乏任何顺序保证意味着 Java SE 的未来版本可以更改顺序。)
为了避免等待任何一个套接字,您不要尝试一次性填满缓冲区;相反,您可以在不阻塞的情况下读取套接字可以提供的任何内容,每次调用只读取一次select()
。
由于每个 ByteBuffer 可能保存部分数据序列,因此您需要记住每个 Socket 的每个 ByteBuffer 的进度。幸运的是,SelectionKey 有一个方便的方法来做到这一点:附件。
您还想记住从每个套接字读取了多少字节。因此,现在您需要记住每个套接字的两件事:字节数和字节缓冲区。
class ReadState {
final ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
long count;
}
while (true) {
// ...
if (key.isAcceptable()) {
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
// Attach the read state for this socket
// to its corresponding key.
socketChannel.register(selector, SelectionKey.OP_READ,
new ReadState());
}
if (key.isReadable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
ReadState state = (ReadState) key.attachment();
ByteBuffer buffer = state.buffer;
state.count += socketChannel.read(buffer);
if (state.count >= DATA_LENGTH) {
socketChannel.close();
}
buffer.flip();
// Caution: The speed of this connection will limit your ability
// to process the remaining selected keys!
anotherServerChannel.write(buffer);
}
对于阻塞通道,您可以只使用一次write(buffer)调用,但是正如您所看到的,使用阻塞通道可能会限制主服务器使用非阻塞通道的优势。将与其他服务器的连接也设置为非阻塞通道可能是值得的。这会让事情变得更加复杂,所以除非你希望我这样做,否则我不会在这里解决这个问题。
添加回答
举报