Selector的施用

Selector的使用

在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仍会存在。
			}
		}
	}
}

客户端:

Selector的施用Selector的施用


输出:

Selector的施用

Selector的施用


Selector的施用

Selector的施用