NIO实例

Posted on 2011-01-27 11:53  胡安峰  阅读(470)  评论(0编辑  收藏  举报

import java.net.InetSocketAddress;
import java.net.ServerSocket;
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;

/**
 * 通过ServerSocketChannel.open()获得一个Server的Channel对象。 通过Selector.open()来获得一个Selector对象。
 * 从Server的Channel对象上可以获得一个Server的Socket,并让它在80端口监听。
 * 通过ServerSocketChannel.configureBlocking(false)可以将当前的Channel配置成异步非阻塞的方式。如果没有这一步,那么Channel默认的方式跟传统的一样,是阻塞式的。
 * 将当前的Channel注册到Selector对象中去,并告诉Selector当前的Channel关心的操作是OP_ACCEPT,也就是当有新的请求的时候,Selector负责更新此Channel的状态。
 * 在循环当中调用selector.select(),如果当前没有任何新的请求过来,并且原来的连接也没有新的请求数据到达,这个方法会阻塞住,一直等到新的请求数据过来为止。
 * 如果当前都请求的数据到达,那么selector.select()就会立刻退出,这时候可以从selector.selectedKeys()获得所有在当前selector注册过的并且有数据到达的这些Channel的信息(SelectionKey)。
 * 遍历所有的这些SelectionKey来获得相关的信息。如果某个SelectionKey的操作是OP_ACCEPT,也就是isAcceptable,那么可以判定这是那个Server Channel,并且是有新的连接请求到达了。
 * 当有新的请求来的时候,通过accept()方法可以获得新的channel服务于这个新来的请求。然后通过configureBlocking(false)可以将当前的Channel配置成异步非阻塞的方式。
 * 接着将这个新的channel也注册到selector中,并告诉Selector当前的Channel关心的操作是OP_READ,也就是当前Channel有新的数据到达的时候,Selector负责更新此Channel的状态。
 * 如果在循环当中发现某个SelectionKey的操作是OP_READ,也就是isReadable,那么可以判定这不是那个Server
 * Channel,而是在循环内部注册的连接Channel,表明当前SelectionKey对应的这个Channel有数据到达了。
 * 有数据到达之后的处理方式是下面要详细讨论的问题,在这里,我们简单地用一个方法readDataFromSocket(key)来表示,功能就是从这个Channel中读取数据。
 *
 * @author Administrator
 */
public class NIOSocketServer {

    public static void main(String[] argv) throws Exception {
        // 可以通过配套这个参数来选择自己的selector -Djava.nio.channels.spi.SelectorProvider=
        System.out.println(System.getProperty("java.nio.channels.spi.SelectorProvider"));

        ServerSocketChannel serverCh = ServerSocketChannel.open();
        System.out.println(serverCh);
        // 通过调用此类的 open 方法创建选择器,该方法将使用系统的默认选择器提供程序创建新的选择器。也可通过调用自定义选择器提供程序的 openSelector 方法来创建选择器。通过选择器的 close
        // 方法关闭选择器之前,它一直保持打开状态。

        Selector selector = Selector.open();
        ServerSocket serverSocket = serverCh.socket();
        serverSocket.bind(new InetSocketAddress(800));
        serverCh.configureBlocking(false);
        serverCh.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            // 则在 Selector.select()上就会始终有事件出现,CPU就一直处理了,而此时select()应该是阻塞的。
            selector.select();
            Iterator it = selector.selectedKeys().iterator();
            while (it.hasNext()) {
                SelectionKey key = (SelectionKey) it.next();
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    System.out.println(key);
                    SocketChannel channel = server.accept();
                    channel.configureBlocking(false);
                    // 接着将这个新的channel也注册到selector中,并告诉Selector当前的Channel关心的操作是OP_READ,OP_WRITE
                    channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
                }
                // System.out.println(key.isWritable());
                if (key.isReadable()) {
                    SocketChannel sChannel = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    sChannel.read(buffer);
                    buffer = (ByteBuffer) buffer.flip();
                    byte[] b = new byte[buffer.limit()];
                    buffer.get(b);
                    System.out.println(new String(b));
                    // sChannel.configureBlocking(true);
                    // System.out.println(new String(buffer.duplicate().array()));

                    buffer.clear();
                    buffer.put("<html><body>hello</body></html>".getBytes());
                    buffer.flip();
                    sChannel.write(buffer);
                    // 关闭此通道。否则会出现死循环
                    sChannel.close();
                    // sChannel.finishConnect();
                    // System.out.println(sChannel.isConnected());
                }
                // else if (key.isWritable()) {
                // SocketChannel sChannel = (SocketChannel) key.channel();
                // // sChannel.configureBlocking(true);
                // ByteBuffer buffer = ByteBuffer.allocate(100);
                // buffer.put("<html><body>hello</body></html>".getBytes());
                // buffer.flip();
                // sChannel.write(buffer);
                // sChannel.close();
                // // sChannel.finishConnect();
                // // System.out.println(sChannel.isConnected());
                // }
                it.remove();

            }

        }

    }
}