zoukankan      html  css  js  c++  java
  • java NIO之SelectedKey

        SelectedKey是channel与Selector绑定的标记,每将一个channel注册到一个selector就会产生一个SelectedKey,并将这个SelectedKey放入到Selected的key set中,注意,key set 只能通过这种方式添加,不可以直接添加,但是可以手动移除。

        SelectedKey存在着两个集合,分别是interest set和ready set,二者的元素类型都是整数值,每一位代表一个标记,代表该key对应的channel支持/准备好什么操作。interest set在SelectedKey被创建时(channel注册时)指定,记录了此key对应的channel支持什么操作(accept,write,read,connect等),并且可以在以后通过interestOpt(int)改变;ready set则记录了此SelectedKey已经准备好了什么样的操作,ready set的值由selector设置和更新,不可以由用户去改变。ready set指定的操作说明该种操作已经就绪好,可以实行非阻塞操作了,但是不保证之后该key状态没有被修改(比如channel被关闭),如果之后key状态被改变又没有通过select操作更新(参见java.nio.channels.Selector),则操作可能依然会阻塞线程。

        SelectedKey为每种操作标记都定义了一个静态常量值,但是一个key具体指示什么操作,是由对应的channel决定的,SelectedChannel的各个子类都有自己所支持的操作,如果注册时被制定了不支持的操作,将会发生运行时错误。

        SelectedKey还为应用程序提供了一个附件区,可用于存放上层应用协议相关的数据,比如协议状态等。这个附件区是一个单独的对象,用attach设置,attachment获取。

        SelectedKey本身不是线程安全的,但是,操作它的selector要求实现同步措施,对数据的读写加上不同程度的同步锁。也就是说,同步策略交给具体的selector实现去做。

    典型的NIO socket服务端代码如下所示:

    public class PlainNioServer {
        public void serve(int port) throws IOException {
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            serverChannel.configureBlocking(false);
            ServerSocket ss = serverChannel.socket();
            InetSocketAddress address = new InetSocketAddress(port);
            ss.bind(address); //1
            Selector selector = Selector.open(); //2 
            serverChannel.register(selector, SelectionKey.OP_ACCEPT); //3 
            final ByteBuffer msg = ByteBuffer.wrap("Hi!
    ".getBytes());
            for (; ; ) {
                try {
                    selector.select(); //4 
                } catch (IOException ex) {
                    ex.printStackTrace();
                    // handle exception 
                    break;
                }
                Set<SelectionKey> readyKeys = selector.selectedKeys(); //5 
                Iterator<SelectionKey> iterator = readyKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    try {
                        if (key.isAcceptable()) { //6 
                            ServerSocketChannel server = (ServerSocketChannel) key.channel();
                            SocketChannel client = server.accept();
                            client.configureBlocking(false);
                            client.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, msg.duplicate()); //7
                            System.out.println("Accepted connection from " + client);
                        }
                        if (key.isWritable()) { //8 
                            SocketChannel client = (SocketChannel) key.channel();
                            ByteBuffer buffer = (ByteBuffer) key.attachment();
                            while (buffer.hasRemaining()) {
                                if (client.write(buffer) == 0) { //9 
                                    break;
                                }
                            }
                            client.close(); //10 
                        }
                    } catch (IOException ex) {
                        key.cancel();
                        try {
                            key.channel().close();
                        } catch (IOException cex) { // 在关闭时忽略 
                        }
                    }
                }
            }
        }
    }
  • 相关阅读:
    MySQL 多会话之间更新数据的小实例
    MySQL Profile
    MySQL Explain
    MySQL 索引
    利用网站上传漏洞使用一句话木马控制服务器
    kali之nmap
    kali之使用sqlmap进行sql注入
    kali之DVWA
    Kali安装nessus
    openvas
  • 原文地址:https://www.cnblogs.com/JMLiu/p/8451464.html
Copyright © 2011-2022 走看看