NIO selector多路复用器
2020-04-27 00:13
369 查看
- 基本流程与C语言一样:
-
socket 设置非阻塞、bind绑定端口、listen监听连接、epoll_create、添加socket到epoll监听EPOLLIN、epoll_wait等待连接事件就绪的连接
accpet新连接。得到socket且设置非阻塞、添加到epoll监听EPOLLIN
- 新的socket EPOLLIN事件就绪。读取数据。
如果程度是
-1
说明客户端关闭连接。JAVA中需要调用 channel.cancel() - 否则是正常数据输入
- selectionKey.remove()
public void testScannerServer() throws IOException { System.out.println("服务端开启"); ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 非阻塞 serverSocketChannel.configureBlocking(false); serverSocketChannel.bind(new InetSocketAddress(8092)); Selector selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (selector.select() > 0) { // it won't clear the existing items 不会清空已经存在的 selectionKey。因此遍历处理一个后需要remove移除 Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = it.next(); // 为什么要remove?因为 select 就绪队列,如果不移除就会一直存在 // https://stackoverflow.com/questions/7132057/why-the-key-should-be-removed-in-selector-selectedkeys-iterator-in-java-ni it.remove(); if (!key.isValid()) { System.out.println("连接不可用"); } else if (key.isAcceptable()) { // 新连接 System.out.println("服务端接受到新连接"); SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); // 非阻塞 socketChannel.register(selector, SelectionKey.OP_READ); // 注册可读事件 } else if (key.isReadable()) { // 有客户端发送数据 SocketChannel socketChannel = (SocketChannel) key.channel(); // 开始读取数据 System.out.println(new Date().toString()); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); if (socketChannel.read(byteBuffer) == -1) { // -1 说明客户端关闭了写或者直接close System.out.println("客户端关闭连接"); // socketChannel.close(); // 其实不需要调用,因为客户端已经关闭, 为了程序稳健性可以开启 key.cancel(); // 取消注册 } else { byteBuffer.flip(); System.out.println(new String(byteBuffer.array(), 0, byteBuffer.limit())); byteBuffer.clear(); } } } } }