• Java NIO学习笔记-Selector


    Selector选择器是什么

    Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。

    Java NIO的选择器部分,实际上有三个重要的类:

    • Selector 选择器,完成主要的选择功能,维护着注册的一组SelectionKey。
    • SelectableChannel 记录了一组注册的SelectionKey[]。
    • SelectionKey 关联了一个Channel和一个Selector,描述一个Selector和SelectableChannel的关系。并保存有通道所关心的操作。

    Selector

    更新准备好的SelectionKey,移除isValid()为false的SelectionKey

    • select() //阻塞等待,直至一个channel准备好或调用wakeup()才返回
    • select(long timeout) //如上,返回条件多了个超时时间
    • selectNow() //非阻塞,会立刻返回,没有时返回值=0
    • wakeup() //使得Selector返回

    SelectionKey

    兴趣操作集,通过它就可以知道channel可以去做哪些事了.有4种类型,如下:

    • public static final int OP_READ = 1 << 0;
    • public static final int OP_ACCEPT = 1 << 4;
    • public static final int OP_WRITE = 1 << 2;
    • public static final int OP_CONNECT = 1 << 3;
      通过SelectionKey.interestOps(int ops)就可以配置这些值

    SelectionKey

    • SelectionKey.attach(Object ob) //添加附件,另一种方式SelectableChannel.register(Selector sel, int ops, Object att)
    • SelectionKey.attachment() //获取附件
    • SelectionKey.cancel(),永久的注销键,加入Selector的注销集中,在下次select()时被移除

    完整实例

    @Test
    public void client() throws IOException {
    	//获取通道
    	SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 7777));
    	//切换成非阻塞模式
    	socketChannel.configureBlocking(false);
    	//分配缓冲区
    	ByteBuffer buffer = ByteBuffer.allocate(1024);
    	//发送数据给服务端
    	Scanner scanner = new Scanner(System.in);
    	while (scanner.hasNext()) {
    		String str = scanner.next();
    		buffer.put((LocalDateTime.now().toString().getBytes() + ":" + str).getBytes());
    		buffer.flip();
    		socketChannel.write(buffer);
    		buffer.clear();
    	}
    	//关闭通道
    	socketChannel.close();
    }
    
    @Test
    public void server() throws IOException {
    	//获取通道
    	ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    	//切换非阻塞模式
    	serverSocketChannel.configureBlocking(false);
    	//绑定连接
    	serverSocketChannel.bind(new InetSocketAddress(7777));
    	//获取选择器
    	Selector selector = Selector.open();
    	//将通道注册到选择器
    	//可以监听的事件类型
    	//读 SelectionKey.OP_READ  1
    	//写 SelectionKey.OP_WRITE 4
    	//连接 SelectionKey.OP_CONNECT  8
    	//接收SelectionKey.OP_ACCEPT 16
    	serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    	//轮询获取选择器上已经准备就绪的事件
    	while (selector.select() > 0) {
    		//获取当前选择器中所有注册的选择键(已就绪的监听事件)
    		Set<SelectionKey> selectedKeys = selector.selectedKeys();
    		Iterator<SelectionKey> iterator = selectedKeys.iterator();
    		while (iterator.hasNext()) {
    			//获取准备就绪的事件
    			SelectionKey selectionKey = (SelectionKey) iterator.next();
    			//判断具体是什么事件准备就绪
    			if (selectionKey.isAcceptable()) {
    				//若接收就绪,就获取客户端的连接
    				SocketChannel socketChannel = serverSocketChannel.accept();
    				//切换非阻塞模式
    				socketChannel.configureBlocking(false);
    				//将该通道注册到选择器上
    				socketChannel.register(selector, SelectionKey.OP_READ);
    			} else if (selectionKey.isReadable()) {
    				//若读就绪,获取当前选择器上读就绪状态的通道
    				SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
    				//读取数据
    				ByteBuffer buffer = ByteBuffer.allocate(1024);
    				int length = 0;
    				while ((length = socketChannel.read(buffer)) > 0) {
    					buffer.flip();
    					System.out.println(new String(buffer.array(), 0, length));
    					buffer.clear();
    				}
    			}
    			//取消选择键 SelectionKey
    			iterator.remove();
    		}
    	}
    }
    

    参考:http://www.cnblogs.com/bronte/articles/1966550.html
    http://ifeve.com/selectors/

    代码托管:https://git.oschina.net/umgsai/java-nio

  • 相关阅读:
    内网渗透之文件下载
    从跨域与同源策略谈CSRF防御与绕过
    内网渗透之权限维持
    一次关于shiro反序列化漏洞的思考
    冰蝎&哥斯拉 流量特征分析
    第三方提权之数据库提权
    APP渗透测试之安卓APP抓包
    从零开始的信息搜集(二)
    从零开始的信息搜集(一)
    python 进程
  • 原文地址:https://www.cnblogs.com/umgsai/p/6684091.html
Copyright © 2020-2023  润新知