目录
一、服务端代码示例
- 一、服务端代码示例
- 二、客户端代码示例
- 三、启动一个客户端测试
- 四、启动2个客户端测试
- 五、事件发生后能否不处理
-
服务端代码示例
package com.example.nettytest.nio.day3; import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; /** * @description: Selector处理accept事件 代码示例 * @author: xz * @create: 2022-09-01 */ @Slf4j public class Test2Server { public static void main(String[] args) { nioSelectorAcceptServer(); } /** * Selector处理accept事件 方法 * */ private static void nioSelectorAcceptServer(){ try (ServerSocketChannel channel = ServerSocketChannel.open()) {//1、创建服务器 //绑定监听端口 channel.bind(new InetSocketAddress(8080)); //设置为非阻塞模式 channel.configureBlocking(false); System.out.println("channel=="+channel); /** * 2、创建Selector,管理多个channel */ Selector selector = Selector.open(); /** * 3、建立Selector与channel的联系(也称为注册) * key只关注事件,绑定的事件类型4种,connect - 客户端连接成功时触发;accept - 服务器端成功接受连接时触发; read - 数据可读入时触发;write - 数据可写出时触发, * */ channel.register(selector, SelectionKey.OP_ACCEPT); while(true){ /** * 3、select 方法, 没有事件发生,线程阻塞,有事件,线程才会恢复运行 * select 在事件未处理时,它不会阻塞 */ int count = selector.select(); log.debug("select count: {}", count); // 获取所有事件 Set keys = selector.selectedKeys(); // 遍历所有事件,逐一处理 Iterator iterator = keys.iterator(); //遍历所有事件,逐一处理 while(iterator.hasNext()){ SelectionKey key = iterator.next(); log.info("key===={}",key); // 判断事件类型,如果事件类型是 accept - 服务器端成功接受连接时触发; if (key.isAcceptable()) { //channel中有哪些key ServerSocketChannel c = (ServerSocketChannel) key.channel(); //必须处理 selector 上的 channel SocketChannel sc = c.accept(); log.debug("sc==={}", sc); } // 处理完毕,必须将事件移除 iterator.remove(); } } } catch (IOException e) { e.printStackTrace(); } } }
-
客户端代码示例
package com.example.nettytest.nio.day3; import java.io.IOException; import java.net.Socket; /** * @description: * @author: xz * @create: 2022-09-01 */ public class Test2Client { public static void main(String[] args) { try (Socket socket = new Socket("localhost", 8080)) { System.out.println(socket); socket.getOutputStream().write("hello world".getBytes()); System.in.read(); } catch (IOException e) { e.printStackTrace(); } } }
-
先启动服务端 由下图输出结果可知,由于没有事件发生,再select 方法处,线程阻塞。
-
再启动客户端
-
再查看服务端控制台输出 由下图输出结果可知,由于有事件发生,再select 方法处,线程会恢复运行。
- 再启动一个客户端
- 再次查看服务端控制台输出 由下图输出结果可知,由于有事件发生,再select 方法处,线程再次恢复运行。并且服务端2次接受的key是同一个对象。
- 事件发生后,要么处理,要么取消(cancel),不能什么都不做,否则下次该事件仍会触发,这是因为 nio 底层使用的是水平触发。