典型代码
public void Server() throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(1024);
Selector selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);//设置为非阻塞方式
ssc.socket().bind(new InetSocketAddress(8080));
ssc.register(selector, SelectionKey.OP_ACCEPT);//注册监听的事件,这里只对新连接感兴趣
//循环检测
while (true) {
//获得注册的keys
selector.selectorNow();
Set selectedKeys = selector.selectedKeys();//取得所有key集合
Iterator it = selectedKeys.iterator();
while (it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
if (key.isAcceptable()) {
ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel();
//处理这个事件,SelectionKey 将会把accpet状态从ready中移除
SocketChannel sc = ssChannel.accept();//接受到服务端的请求
sc.configureBlocking(false);
}
//用完之后,把它selector的就绪selectedKeys中移除
it.remove();
}
}
}
核心点
-
Selector
定义了用于多路复用的、非阻塞 I/O 操作的选择器。一个Selector监听一组Channel
的I/O状态变化,实现了一个线程处理多个SocketChannel
。
Selector
可以调用 select() 方法检查已经注册的通信信道上的是否有 I/O 已经准备好,如果没有至少一个信道 I/O 状态有变化,那么 select 方法会阻塞等待或在超时时间后会返回 0。 -
SocketChannel
和ServerSocketChannel
的configureBlocking(false)
可实现非阻塞操作 - 通过在
channel
的register(Selector sel, int ops)
向Selector注册,每次向选择器注册通道都会返回一个SelectionKey。
selector.png
SelectionKey解析
保存channel在selector注册的事件。
选择键包含两个表示为整数值的操作集。操作集的每一位都表示该键的通道所支持的一类可选择操作,,其中ops是SelectionKey的4个常量的值。可以同时关注多个操作,通过位的或运算,例如int ops = SelectionKey.OP_READ | SelectionKey.OP_WRITE
1.OP_READ 用于读操作的操作集位
2.OP_WRITE 用于写操作的操作集位
3.OP_CONNECT 用于套接字连接操作的操作集位。
4.OP_ACCEPT 用于套接字接受操作的操作集位
获取设置感兴趣的操作
通过操作interest集合
interestOps()
返回interset集合
interestOps(ops)
设置interset集合
获取已就绪的操作
通过操作ready集合
readyOps()
获取readyOps
测试通道操作是否就绪
API | 原理 |
---|---|
isAcceptable() |
是否准备好读操作了 与k.readyOps() & OP_READ != 0 等价 |
isWritable() |
是否准备好写操作了 与k.readyOps() & OP_WRITE != 0 等价 |
isConnectable |
channel是否已完成套接字连接 与k.readyOps() & OP_CONNECT != 0 等价 |
isReadable() |
测试此键的通道是否已准备好接受新的套接字连接。 与k.readyOps() & ACCEPT != 0 等价 |
获取channel
调用channel()
获取selector
调用selector()
关闭channel
调用cancel()
,关闭通道
通过调用某个键的
cancel
方法、关闭其通道,或者通过关闭其选择器来取消 该键之前,它一直保持有效。取消某个键不会立即从其选择器中移除它;相反,会将该键添加到选择器的已取消键集,以便在下一次进行选择操作时移除它。可通过调用某个键的isValid
方法来测试其有效性。
内部原理
interest 集合 下一次调用select()
时,将测试哪类操作的准备就绪信息。创建该键时使用给定的值初始化 interest 集合;之后可通过interestOps(int) 方法对其进行更改。
ready 集合 标识了这样一类操作,即某个键的选择器检测到该键的通道已为此类操作准备就绪。创建该键时 ready 集合被初始化为零;可以在之后的选择操作中通过选择器对其进行更新,但不能直接更新它。(已就绪的操作)
附加对象
可通过 attach
方法附加对象,然后通过 attachment
方法获取该对象
通常必须将某个特定于应用程序的数据与某个选择键相关联,例如表示高级协议状态的对象和为了实现该协议而处理准备就绪通知的对象。因此,选择键支持将单个任意对象附加 到某个键的操作。
经典操作
网友评论