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