了解nio的selector

学习nio,最费解是selector,为了了解这个东西,花了不少时间看博文。为此我将我的学习理解过程记录了下来

1、什么是selector?

Selector选择器,channel可以在Selector上注册,并绑定选择键SelectorKey,同时可以添加一个附加的对象进行标志。他能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。

2、那些channel可以在selector上注册?

FileChannel,针对文件IO的Channel是不支持selector的,selector需要实现SelectableChannel接口的channel,在jdk的继承中有如下几个类:DatagramChannel, Pipe.SinkChannel, Pipe.SourceChannel, ServerSocketChannel, SocketChannel

3、练习

网上案例基本是针对ServerSocketChannel建立的selector,练习当然不能只按别人的路子走,我在上面几个类中选择了DatagramChannel作为练习的channel。

/**
 * 
 * @author rain-bean
 *
 */
public class CustomerTest {
    private static Selector selector;
    private static DatagramChannel channel;
    private static DatagramChannel channel2;
    
    public static void openChanel() throws IOException{
        
        channel = DatagramChannel.open();
        channel.socket().bind(new InetSocketAddress(9999));        
        //与Selector一起使用时,Channel必须处于非阻塞模式下
        channel.configureBlocking(false);
        //通过open()方法找到Selector
        selector = Selector.open();

        SelectionKey key = channel.register(selector, SelectionKey.OP_READ); //经检测DatagramChannel并不能注册所有的key
        System.out.println("等待连接");    
    }
    
    //监听
    private static void listen() throws IOException{
        boolean bl = true;
        while(bl){
            // 选择一组键,并且相应的通道已经打通。阻塞线程
            selector.select();
            
            //获取注册的key
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            
            //处理感兴趣的key
            while(iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();

                if(selectionKey.isReadable()){
                    ByteBuffer buffer =ByteBuffer.allocate(60);  
                    channel.receive(buffer);
                    System.out.println("读取:"+ new String(buffer.array(),"utf-8")); //中文转码
                    System.out.println("文件读取完毕");
                    bl = false;
                }
            }
        }
    }
    
    /**
     * 发送数据
     * @throws IOException
     */
    private static void send() throws IOException{   
        channel2 =DatagramChannel.open();  
        ByteBuffer buffer = ByteBuffer.wrap("雨水打在窗台的铝架上,哔哔哒哒的".getBytes("utf-8"));  //中文需要转码
        channel2.send(buffer, new InetSocketAddress("localhost",9999));                   
    }  
    
    public static void main(String[] args) throws IOException{
        CustomerTest.openChanel();
        //先send后listen,因为selector会阻塞,当然最好是另起一个线程,分服务和客户端
        CustomerTest.send();
        CustomerTest.listen();
        channel.close();
        channel2.close(); 
    }
          
}

4、总结

经过练习对selector加深了解,也发现并不是channel可以随意注册事件,他的应用应该是为了多路复用传输,而不是为了对文件的不阻塞操作。实例可以进一步深化,编写服务和客户端进行多channel的操作。时间有限,及时行乐,我就不写了。

最后理解错误之处请之处。

posted @ 2017-04-02 14:26  Rainbean  阅读(431)  评论(0编辑  收藏  举报