目录
Selector模型
SelectableChannel
Channel注册到Selector
SelectionKey
遍历SelectionKey
事件驱动
责任链模式
Selector模型
Java NIO是基于Selector模型来实现非阻塞IO,Netty底层基于Java NIO实现的,因此也使用了Selector模型。
Selector提供了选择执行已经就绪的任务的能力。从底层看,Selector会轮询Channel是否已经准备好执行每个IO操作。Selector允许单个线程处理多个Channel。
SelectableChannel
并不是所有的Channel都是可以被Selector复用的,只有抽象类SelectableChannel的子类才能被Selector复用。FileChannel就不能被复用,因其不是SelectableChannel的子类。
SelectableChannel并发安全。
Channel注册到Selector
/*
*Registers this channel with the given selector, returning a selection
* key.
*@param sel
* The selector with which this channel is to be registered
*
* @param ops
* The interest set for the resulting key
*
* @param att
* The attachment for the resulting key; may be <tt>null</tt>
**/
public final SelectionKey register(Selector sel, int ops)
public abstract SelectionKey register(Selector sel, int ops, Object att)
可供Selector查询的通道操作主要有四种:
public static final int OP_READ = 1 << 0;
public static final int OP_WRITE = 1 << 2;
public static final int OP_CONNECT = 1 << 3;
public static final int OP_ACCEPT = 1 << 4;
- 某个SocketChannel通道可以连接到一个服务器,则处于OP_CONNECT状态
- 一个ServerSocketChannel服务器通道准备好接收新接入的连接,则处于OP_ACCEPT状态
- 一个有数据可读的Channel,OP_READ状态
- 一个等待写数据的通道,OP_WRITE状态
SelectionKey
Channel和Selector关系确定好之后,一旦Channel处于某种就绪状态,就可以被选择器查询到,使用Selector.select()方法。
获取感兴趣的事件集合:
public abstract int interestOps();
获取通道已经准备就绪的操作的集合:
public abstract int readyOps();
从SelectionKey访问Channel和Selector:
selectionKey.channel();
selectionKey.selector();
可以将一个对象或其他信息附着到SelectionKey上:
selectionKey.attach(theObject);
selectionKey.attachment();
channel.register(selector, SelectionKey.OP_READ, theObject)
遍历SelectionKey
Selector selector = Selector.open();
ByteBuffer buffer = ByteBuffer.allocate(16);
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
serverSocketChannel.bind(new InetSocketAddress(8080));
while (true) {
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
if(selectionKey.isAcceptable()) {
ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = channel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
}
if(selectionKey.isReadable()) {
SocketChannel channel = (SocketChannel) selectionKey.channel();
channel.read(buffer);
buffer.flip();
ByteBufferUtil.debugAll(buffer);
buffer.clear();
}
iterator.remove();
}
}
每次迭代记得调用iterator.remove。
事件驱动
Netty是异步的事件驱动网络应用框架。