非阻塞I/O–Java NIO教程

来源:互联网 发布:淘宝销量少的可以买吗 编辑:程序博客网 时间:2024/05/22 16:59

转载请标明:http://blog.geekcome.com/archives/261

Java NIO核心组件:

  • channels
  • Buffers
  • Selectors

虽然NIO还有其他的组件,上面的三个是核心。

Channel

基本上,所以的IO在NIO中都是从一个Channel开始。Channel有点像流(Stream),数据可以从Channel读取到Buufer,也可以从Buffer写到Channel。Channel有下面的几种类型:

  • FileChannel(文件IO)
  • DatagramChannel(UDP数据报IO)
  • SocketChannel(TCP数据报IO)
  • ServerSocketChannel(监听新进来的TCP链接)

Channel和流的区别:

  • Channel可以是双向的,流一般是单向的
  • Channel可以异步的读写
  • Channel总是需要Buffuer来读写数据

ServerSocketChannel:

1ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
2serverSocketChannel.socket().bind(new InetSocketAddress(9999));
3while(true){
4    SocketChannel socketChannel =
5            serverSocketChannel.accept();
6    //do something with socketChannel...
7}

ServerSocketChannel:

1socketChannel.configureBlocking(false);
2socketChannel.connect(new InetSocketAddress("http://jenkov.com"80));
3 
4while(! socketChannel.finishConnect() ){
5    //wait, or do something else...
6}

Buffer

NIO中Buffer的类型:

  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer
  • Mappeddyteuffer

这些Buffer覆盖了你能通过IO发送的数据基本类型,顾名思义。

使用Buffer的四个步骤:

  • 写入数据到Buffer
  • 调用flip()函数
  • 从Buffer中读取数据
  • 调用clear()函数
01RandomAccessFile aFile = new RandomAccessFile("/home/yan/pci1","rw");
02        FileChannel channel = aFile.getChannel();
03 
04        ByteBuffer buf = ByteBuffer.allocate(20);
05 
06        int res = channel.read(buf);
07        while(res != -1){
08            buf.flip();
09            while(buf.hasRemaining()){
10                System.out.println((char)buf.getChar());
11            }
12            buf.clear();
13 
14            res = channel.read(buf);
15        }

Buffer还支持多个Buffer组成缓冲数组,对其进程读写操作。

Selector

Selector允许单线程处理多个Channel(一个Channel就是一个连接),如果每个连接的流量都很小,使用Selector就会很方便,如上图所示。而不用每个Channel来新建一个线程处理。

要使用Selector,首先要进程注册,想selector注册Channel,然后调用selector的select方法。这个方法会阻塞到某个注册的事件就绪,一旦这个方法返回,线程就可以处理这些事件。

创建Selector

调用Selector.open()方法来创建一个Selector:

1Selector selector = Selector.open()

像Selector注册通道:

1channel.configureBloacking(false);
2SelectionKey key = channel.register(selector,SeletionKey.OP_READ);

SelectionKey

SelectionKey对象中含有如下属性:

  • interest集合(使用&操作SelectionKey.OP_ACCEPT和key.interestOps())
  • ready集合(key.readyOps(),可以使用&操作检测该集合,也可以使用is方法)
  • Channel(key.channel())
  • Selector(key.selector())
  • 附加对象(key.attach(obj)   Object obj = key.attachment())

selector通道选择

  • int select()//阻塞
  • int select(long timeout)//超时之前阻塞
  • int selectNow()//不阻塞

selectedKeys()

一单调用select方法并且返回了,说明有一个或多个通道就绪了,然后通过该方法选择已经就绪的集合,然后遍历这些集合对每个通道进行处理。

01Set selectedKeys = selector.selectedKeys();
02Iterator keyIterator = selectedKeys.iterator();
03while(keyIterator.hasNext()) {
04    SelectionKey key = keyIterator.next();
05    if(key.isAcceptable()) {
06        // a connection was accepted by a ServerSocketChannel.
07    else if (key.isConnectable()) {
08        // a connection was established with a remote server.
09    else if (key.isReadable()) {
10        // a channel is ready for reading
11    else if (key.isWritable()) {
12        // a channel is ready for writing
13    }
14    keyIterator.remove();
15}


参考文章:http://tutorials.jenkov.com/java-nio/overview.html

0 0