zoukankan      html  css  js  c++  java
  • java nio(reactor, selector, selectionKey)

    SocketChannel vs. ServerSocketChannel

    • 父类:SelectableChannel。Channel表现了一个可以进行IO操作的通道(比如,通过FileChannel,我们可以对文件进行读写操作)
    • ServerSocketChannel主要用在Server中,用于接收客户端的链接请求
      SocketChannel则用于真正的读写数据,同时还可以用于客户端发送链接请求。
    • 真正实现读写数据操作的就是这些SocketChannel,上面的ServerSocketChannel只是负责接收连接请求。
    • 以下均简称为channel

    channel vs. Selector

    • channel需要注册到selector上。channel可以注册到一个或多个Selector上以进行异步IO操作。

           channel.register(selector, SelectionKey.OP_ACCEPT);

           channel.register(selector, xxx, object); //attachment被存放在返回的SelectionKey中

           channel.keyFor(selector); //返回该channe在Selector上的注册关系所对应的SelectionKey。若无注册关系,返回null。

    • Selector可以同时监控多个SelectableChannel的IO状况,是异步IO的核心。

           Selector.open(); //静态方法,创建一个selector实例

           selector.select(); //selector通过调用select(),将注册的channel中有事件发生的取出来进行处理。监控所有注册的channel,当其中有注册的IO操作可以进行时,该函数返回,并将对应的SelectionKey加入selected-key set。

           selector.keys(); //所有注册在这个Selector上的channel

           selector.selectedKeys(); //所有通过select()方法监测到可以进行IO操作的channel

    SelectionKey

    • 代表了Selector和SelectableChannel的注册关系

           key.attachment(); //返回SelectionKey的attachment,attachment可以在注册channel的时候指定。

           key.channel(); // 返回该SelectionKey对应的channel。

           key.selector(); // 返回该SelectionKey对应的Selector。

           key.interestOps(); //返回代表需要Selector监控的IO操作的bit mask

           key.readyOps(); //返回一个bit mask,代表在相应channel上可以进行的IO操作。

    Demo1: Server端底层如何接受连接

       int n = selector.select();                                   // 得到selector所捕获的事件数量
       if( n > 0 ){                                                        // 当真正捕获到事件时,才执行相应操作
        Set selectedKeys = selector.selectedKeys();  // 获取捕获到的事件集合
    Iterator i = selectedKeys.iterator();
    while(i.hasNext())              
    {
    SelectionKey s = (SelectionKey) i.next(); // 对事件一一处理

    //一个key被处理完成后,就都被从就绪关键字(ready keys)列表中除去
    i.remove();
    if(s.isAcceptable())                                   // 表示该事件为OP_ACCEPT事件
    {
    // 从channel()中取得我们刚刚注册的ServerSocketChannel。
    // 为请求获取新的SocketChannel
    SocketChannel sc = ((ServerSocketChannel)s.channel()).accept().socket().getChannel(); 

    sc.configureBlocking(false);                 // 设置SocketChannel为非阻塞方式
    sc.register(selector, SelectionKey.OP_READ |SelectionKey.OP_WRITE); 
                           // 将新的SocketChannel注册到selector中,注册事件为OP_READ和OP_WRITE
    }
    else
    {
    // 执行其他操作
    }
      }
       }

    Demo2: Server端底层如何读取channel上的数据

                    SelectionKey s = (SelectionKey) i.next();                          // 对事件一一处理

    //一个key被处理完成后,就都被从就绪关键字(ready keys)列表中除去
    i.remove();
                     ByteBuffer clientBuffer = ByteBuffer.allocate(4096);
    if (key.isReadable()) {                                                               // 读信息
                         SocketChannel channel = (SocketChannel) key.channel();    // 获取相应的SocketChannel
                         int count = channel.read(clientBuffer);                                   // 将数据读入clientBuffer
                         if (count > 0) {                                                                       // 当有数据读入时
                             clientBuffer.flip();                                                               // 反转此缓冲区
                             CharBuffer charBuffer = decoder.decode(clientBuffer);     // 如果需要,对缓冲区中的字符进行解码
                              ...                                                                                     // 处理数据
                         }
                     }

    Demo3: Client端底层如何发起连接、写入数据

       InetSocketAddress addr = new InetSocketAddress(host,port);
       //生成一个socketchannel
       sc = SocketChannel.open();        
       //连接到server
       sc.connect(addr);                       // 连接到server

       if(sc.finishConnect()){                // 当连接成功时,执行相应操作
        ByteBuffer buffer = .....             // 准备数据
        buffer.filp();                              // 反转此缓冲区
        while(w_buff.hasRemaining())  // 发送数据到server
              sc.write(w_buff);

    学习文档:

    http://www.iteye.com/topic/40489

    http://blog.csdn.net/derekjiang/article/details/4465697

    http://blog.csdn.net/derekjiang/article/details/4470175

    http://www.cnblogs.com/freedom-elf/archive/2011/08/11/2135015.html

  • 相关阅读:
    Java 中文 乱码问题
    JQuery 操作 radio 被坑一例
    标准I/O库之打开和关闭流
    标准I/O库之缓冲
    标准I/O库之标准输入、标准输出和标准出错
    标准I/O库之流和FILE对象
    文件和目录之文件访问权限位小结
    文件和目录之设备特殊文件
    文件和目录之chdir、fchdir和getcwd函数
    文件和目录之读目录
  • 原文地址:https://www.cnblogs.com/alipayhutu/p/2483018.html
Copyright © 2011-2022 走看看