java nio(reactor, selector, selectionKey)
SocketChannel vs. ServerSocketChannel
- 父类:SelectableChannel。Channel表现了一个可以进行IO操作的通道(比如,通过FileChannel,我们可以对文件进行读写操作)
- ServerSocketChannel主要用在Server中,用于接收客户端的链接请求
SocketChannel则用于真正的读写数据,同时还可以用于客户端发送链接请求。 - 真正实现读写数据操作的就是这些SocketChannel,上面的ServerSocketChannel只是负责接收连接请求。
- 以下均简称为channel
channel vs. Selector
- channel需要注册到selector上。channel可以注册到一个或多个Selector上以进行异步IO操作。
channel.register(selector, SelectionKey.OP_ACCEPT);
channel.register(selector, xxx, object); //attachment被存放在返回的SelectionKey中
channel.keyFor(selector); //返回该channe在Selector上的注册关系所对应的SelectionKey。若无注册关系,返回null。
- Selector可以同时监控多个SelectableChannel的IO状况,是异步IO的核心。
Selector.open(); //静态方法,创建一个selector实例
selector.select(); //selector通过调用select(),将注册的channel中有事件发生的取出来进行处理。监控所有注册的channel,当其中有注册的IO操作可以进行时,该函数返回,并将对应的SelectionKey加入selected-key set。
selector.keys(); //所有注册在这个Selector上的channel
selector.selectedKeys(); //所有通过select()方法监测到可以进行IO操作的channel
SelectionKey
- 代表了Selector和SelectableChannel的注册关系
key.attachment(); //返回SelectionKey的attachment,attachment可以在注册channel的时候指定。
key.channel(); // 返回该SelectionKey对应的channel。
key.selector(); // 返回该SelectionKey对应的Selector。
key.interestOps(); //返回代表需要Selector监控的IO操作的bit mask
key.readyOps(); //返回一个bit mask,代表在相应channel上可以进行的IO操作。
Demo1: Server端底层如何接受连接
int n = selector.select(); // 得到selector所捕获的事件数量 //一个key被处理完成后,就都被从就绪关键字(ready keys)列表中除去 sc.configureBlocking(false); // 设置SocketChannel为非阻塞方式 |
Demo2: Server端底层如何读取channel上的数据
SelectionKey s = (SelectionKey) i.next(); // 对事件一一处理 //一个key被处理完成后,就都被从就绪关键字(ready keys)列表中除去 |
Demo3: Client端底层如何发起连接、写入数据
InetSocketAddress addr = new InetSocketAddress(host,port); if(sc.finishConnect()){ // 当连接成功时,执行相应操作 |