Selector的施用
Selector的使用
一共有4个兴趣事件:
如果有多个感兴趣的事件,用符号 | 连接即可。
客户端:
在JDK1.4版本增加的nio包以及其子包中有几个比较重要的基本概念,分别是缓冲器(Buffer),通道(Channel)还有选择器(Selector)。选择器允许一个线程处理多个通道,因而提高了系统的可 伸缩性以及灵活性。
不同的通道(比如SocketChannel,ServerSocketChannel)可以注册到同一个选择器中,然后赋予感兴趣的事件(总共4个:读(read),写(write),连接(connect),接受(accept) ),这样,当你感兴趣的事件激活时,选择器就会通知到你。
获取一个选择器对象很简单:
Selector sel = Selector.open(); //打开一个选择器
在该选择器上注册一个通道只需调用通道对象的register方法,第一个参数就是你的选择器对象,第二个参数指明你感兴趣的事件。
channel.register(selector,SelectionKey.OP_ACCEPT | SelectionKey.OP_CONNECT); // channel是一个通道对象,并且必须是非阻塞的
一共有4个兴趣事件:
public static final int OP_READ = 1 << 0; public static final int OP_WRITE = 1 << 2; public static final int OP_CONNECT = 1 << 3; public static final int OP_ACCEPT = 1 << 4;
如果有多个感兴趣的事件,用符号 | 连接即可。
下面用一个简单的实例来使用Selector。
服务器端和客户端的通信:
服务器端代码:
package org.snake.selector; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; public class Main { public static void main(String[] args) throws Exception { ServerSocketChannel ssc = ServerSocketChannel.open(); //打开一个ServerSocketChannel ssc.configureBlocking(false); // 设置该通道为非阻塞模式 ssc.socket().bind(new InetSocketAddress(12345)); //绑定到服务器端口12345 Selector sel = Selector.open(); //打开一个选择器 ssc.register(sel, SelectionKey.OP_ACCEPT ); //将服务器通道注册到打开的选择器中,方法第二个参数指明感兴趣的位域(还有OP_READ,OP_WRITE,OP_CONNECT) while(true) { int acceptChannels = sel.select(); // 返回激活的感兴趣的通道数 if(acceptChannels == 0) continue; Set<SelectionKey> selectedKeys = sel.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while(keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if(key.isAcceptable()) { System.out.printf("isAcceptable\n"); ServerSocketChannel ssch = (ServerSocketChannel)key.channel(); SocketChannel sc = ssch.accept(); //sc 肯定不会为null sc.configureBlocking(false); sc.register(sel, SelectionKey.OP_READ); String msg = "Welcome to NIO World"; ByteBuffer buff = ByteBuffer.allocate(128); buff.put(msg.getBytes()); buff.flip(); sc.write(buff); } else if(key.isConnectable()) { } else if(key.isReadable()) { SocketChannel ssch = (SocketChannel)key.channel(); ByteBuffer buff = ByteBuffer.allocate(128); ssch.read(buff); buff.flip(); while(buff.hasRemaining()) { System.out.print((char)buff.get()); } } else if(key.isWritable()) { } keyIterator.remove(); //处理完一个事件需删除掉,否则下次循环iterator仍会存在。 } } } }
客户端:
输出: