一、概念
选择器(selector)是selectableChannel对象的多路复用器,一个selector可以监控多个selectableChannel的io情况,selector可以实现一个线程单独管理多个channel,selector是非阻塞的核心
二、selector可以监控的事件类型
- connect 客户端连接服务端事件
- accept 服务端接受服务端事件
- read   读事件
- write  写事件  
每次请求都是从客户端连接服务端(connect),服务端开始准备(accept),准备完成后开始读数据,处理完成之后再写数据
三、selector的常用方法

四、nio 的例子
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 
 | //服务端public class NioServer {
 private ServerSocketChannel serverSocketChannel;
 private Selector selector;
 private Integer port = 8080;
 
 NioServer() {
 try {
 serverSocketChannel = ServerSocketChannel.open().bind(new InetSocketAddress(port));
 //设置非阻塞
 serverSocketChannel.configureBlocking(false);
 //创建Selector
 selector = Selector.open();
 //注册tcp 连接事件到 channel
 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
 System.out.println("服务端初始化完成,端口号:" + port);
 } catch (Exception ex) {
 throw new RuntimeException("初始化服务端失败,ex:"+ex);
 }
 }
 
 private void start() {
 try {
 //获取查看selector 管理多少个channel
 while (selector.select() > 0) {
 //走到这里肯定是selector发现channel有变化了,这个大哥把他管理的sekectedKeys拿出来遍历
 Set<SelectionKey> selectionKeys = selector.selectedKeys();
 Iterator<SelectionKey> iterator = selectionKeys.iterator();
 while (iterator.hasNext()) {
 SelectionKey selectionKey = iterator.next();
 //selector 也不知道是什么变化所以就 各种判断一下,是 创建连接、还是准备就绪、还是读取数据、还是写数据、还是关闭连接
 if (selectionKey.isConnectable()) {
 System.out.println("用户建立连接");
 }
 if (selectionKey.isAcceptable()) {
 System.out.println("用户准备就绪");
 ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
 //这样就拿到了发生变化的 socketChannel
 
 SocketChannel accept = serverSocketChannel.accept();
 accept.configureBlocking(false);
 //把客户端的channel 注册到 selector 当客户端的socketChannel发生变化出发读逻辑
 accept.register(selector, SelectionKey.OP_READ);
 }
 if (selectionKey.isReadable()) {
 System.out.println("读数据");
 SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
 //读数据得是由buffer
 ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
 //切换到读模式
 StringBuffer sb = new StringBuffer();
 while (socketChannel.read(byteBuffer) != -1) {
 byteBuffer.flip();
 sb.append(StandardCharsets.UTF_8.decode(byteBuffer));
 byteBuffer.clear();
 }
 System.out.println("来自客户端的问候:" + sb.toString());
 //来个写数据吧
 socketChannel.register(selector,SelectionKey.OP_WRITE);
 }
 if (selectionKey.isWritable()) {
 System.out.println("写数据");
 System.out.println("不会写数据");
 selectionKey.channel().close();
 }
 if (selectionKey.isValid()) {
 System.out.println("关闭数据");
 }
 //把当前的selection移除,因为后面事件还会加入
 iterator.remove();
 }
 }
 } catch (Exception ex) {
 throw new RuntimeException("服务异,ex:", ex);
 }
 
 
 }
 
 public static void main(String[] args) {
 //先定义服务端
 NioServer nioServer = new NioServer();
 //开启服务
 nioServer.start();
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | //客户端public class NioClint {
 
 public static void main(String[] args) throws IOException {
 SocketChannel open = SocketChannel.open();
 open.connect(new InetSocketAddress("127.0.0.1",8080));
 open.configureBlocking(false);
 ByteBuffer byteBuffer =ByteBuffer.allocate(1024);
 byteBuffer.flip();
 String msg ="呵呵,你大爷";
 byteBuffer = ByteBuffer.wrap(msg.getBytes("utf-8"));
 open.write(byteBuffer);
 byteBuffer.clear();
 Socket socket = open.socket();
 SocketChannel channel = socket.getChannel();
 }
 }
 
 
 |