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();
}
}
}
}