学习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的操作。时间有限,及时行乐,我就不写了。
最后理解错误之处请之处。
时间: 2024-10-21 23:28:53