import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectableChannel;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;/** * Author: tz_wl * Date: 2020/9/16 23:46 * Content: 本示例为 select 单线程版本 */public class select01single { //step 01 初始化全局变量 select server port private ServerSocketChannel server=null; private Selector selector =null; private int port =8092; //step 02 initServer 实例化 server selector 并将server注册到select的op_accept上面 private void initServer() throws IOException { server = ServerSocketChannel.open(); server.bind(new InetSocketAddress(port)); server.configureBlocking(false); selector = Selector.open(); server.register(selector, SelectionKey.OP_ACCEPT);//服务端的accept注册到selector } //step 03 start // while (true) { while(select.select(0)>0) { //当有02步骤的服务端注册到select , // 取出 所有的 selectionKeys private void start() throws IOException { initServer(); System.out.println("端口号为:"+ port +" ,服务正在启动中... "); while (true){ //如果selector中有值,说明 server 端有 accept事件到达 select while (selector.select(0)>0){ Set<SelectionKey> keySets = selector.selectedKeys(); Iterator<SelectionKey> iter = keySets.iterator(); while(iter.hasNext()){ SelectionKey key = iter.next(); iter.remove(); if(key.isAcceptable()){ //如果select 是服务端触发的accept acceptHandler(key); }else if(key.isReadable()){ //如果 select 是客户端触发的 readable readHandler(key); } } } } } //04 acceptable // 当服务端有客户端连接 即是有 accetable 事件 , 注册 客户端的事件 到 select (顺带注册一个byteBuffer空间) // 通过 SelectionKey 获取 serverSocketChannel // 配置此serverSocketChannel的客户端socketChannel为非阻塞状态 // 将socketChannel注册为 select 的 readable 并附赠 byteBuffer private void acceptHandler(SelectionKey key) throws IOException { ServerSocketChannel ssc = (ServerSocketChannel)key.channel(); SocketChannel clientChannel = ssc.accept(); clientChannel.configureBlocking(false); ByteBuffer byteBuffer = ByteBuffer.allocate(20000);//注册此处在堆分配内存,不是栈 clientChannel.register(selector,SelectionKey.OP_READ,byteBuffer); System.out.println("----------------------------------"); System.out.println("新客户端"+clientChannel.getRemoteAddress()); System.out.println("----------------------------------"); } //05 处理客户端readable事件 private void readHandler(SelectionKey key) { SocketChannel client = (SocketChannel)key.channel(); ByteBuffer byteBuffer = (ByteBuffer)key.attachment(); byteBuffer.clear(); int count=0; //socketChannel中获取到的个数 try { while (true) { count = client.read(byteBuffer); if (count > 0) { // 如果能够读到 客户端 的值 ,将此值 会写给客户端 byteBuffer.flip(); while (byteBuffer.hasRemaining()) { client.write(byteBuffer); } byteBuffer.clear(); //打扫卫生 } else if (count == 0) { //如果读不到值 ,停止当前循环 break; } else { //如果是-1 也就是客户端不连接了 , 关闭当前客户端 System.out.println(" 客户端断开连接 "+ client.getRemoteAddress()); client.close(); break; } } }catch (IOException ex){ ex.printStackTrace(); } } public static void main(String[] args) throws IOException { select01single select01single = new select01single(); select01single.start(); }}