异步I/O是没有阻塞地读写数据的方法。通常在代码进行read调用时,代码会阻塞直至可供读取的数据。同样,write调用将会阻塞直至数据能够写入。
1、selector是一个对象,可以注册到很多个channel上,监听各个channel上发生的事件,并且能够根据事件情况决定channel读写。这样通过一个线程管理多个channel就可以出来大量网络连接
创建selector:
Selector selector = Selector.open();
注册channel到selector:
channel.configureBlocking(false);
SelectionKey key = chanenl.register(selector, SelecltionKey.OP_READ_;
注意,注册channel必须设置为异步模式才可以。register调用的返回值是selectionKey。这个对象待办这个通道在此selector上的这个注册。当某个selector
通知你某个传入事件时,它是通过提高对应于该事件的SelectionKey来进行的。selectionKey还可以用于取消通过的注册
2、channel和selector
Channel channel = selectionKey.channel();
Selector selector = selectioKey.selector();
demo:
public class MultiPortEcho {
private int ports[];
private ByteBuffer echoBuffer = ByteBuffer.allocate(1024);
public MultiPortEcho(int ports[]) throws IOException {
this.ports = ports;
go();
}
private void go() throws IOException {
//create selector
Selector selector = Selector.open();
//为每个端口打开一个监听,并把这些监听注册到selector中
for(int i = 0; i < ports.length; ++i) {
//打开一个serverSocketChannel
ServerSocketChannel ssc = ServerSocketChnanel.open();
ssc.configureBlocking(false);//设置为非阻塞
ServerSocket ss = ssc.socket();
InetSocketAddress address = new InetSocketAddress(ports[i]);
ss.bind(address); //监听一个端口
//注册到selector
SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("going to listen to " + ports[i]);
}
while(true) {
int num = selector.select();//返回所发生的事件的数量
Set selectedKeys = selector.selectKeys();
Iterator it = selectedKeys.iterator();
while(it.hasNext()) {
SelectionKey key = (SelectionKey)it.next();
//监听新连接,调用readops方法,检查发生了什么类型的事件
if((key.readyOps() & selectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
//接受一个新连接
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
//将新连接注册到selector。
SelectionKey newKey = sc.register(selector, SelectionKey.OP_READ);
it.remove();
System.out.println("got connection from " + sc);
}else if( (key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
SocketChannel sc = (SocketChannel)key.channel();
int bytesEchoed = 0;
while(true) {
echoBuffer.clear();
int r = sc.read(echoBuffer);
if( r <= 0 ) {
break;
}
echoBuffer.flip();
sc.write(echoBuffer);
bytesEchoed += r;
}
System.out.println("echoed" + bytesEchoed + "from" + sc);
it.remove();
// System.out.println( "going to clear" ); // selectedKeys.clear(); // System.out.println( "cleared" );
}
}
static public void main(String args2[]) throws Exception {
String args[]={"9001","9002","9003"};
if (args.length <= 0) {
System.err.println("Usage: java MultiPortEcho port [port port ...]");
System.exit(1);
}
int ports[] = new int[args.length];
for (int i = 0; i < args.length; ++i) {
ports[i] = Integer.parseInt(args[i]);
}
new MultiPortEcho(ports);
}
}
}
}