NIO模式例子

时间:2023-03-09 17:10:19
NIO模式例子

NIO模式主要优势是体现在对多连接的管理,对众多连接各种事件的转发让处理变得更加高效,所以一般是服务器端才会使用NIO模式,而对于客户端为了方便及习惯使用阻塞模式的Socket进行通信。所以NIO模式的例子也仅仅看下服务端的实现即可。

public class NioServer {

private ByteBuffer readBuffer;

private Selector selector;

private void init() {

readBuffer = ByteBuffer.allocate(1024);

ServerSocketChannel servSocketChannel;

try {

servSocketChannel = ServerSocketChannel.open();

servSocketChannel.configureBlocking(false);

servSocketChannel.socket().bind(new InetSocketAddress(8888));

selector = Selector.open();

servSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

} catch (IOException e) {

e.printStackTrace();

}

}

private void listen() {

while (true) {

try {

selector.select();

Iterator ite = selector.selectedKeys().iterator();

while (ite.hasNext()) {

SelectionKey key = (SelectionKey) ite.next();

ite.remove();

handleKey(key);

}

} catch (Throwable t) {

t.printStackTrace();

}

}

}

private void handleKey(SelectionKey key) throws IOException,ClosedChannelException {

SocketChannel channel = null;

try {

if (key.isAcceptable()) {

ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();

channel = serverChannel.accept();

channel.configureBlocking(false);

channel.register(selector, SelectionKey.OP_READ);

} else if (key.isReadable()) {

channel = (SocketChannel) key.channel();

readBuffer.clear();

int count = channel.read(readBuffer);

if (count > 0) {

readBuffer.flip();

ByteBuffer response = ByteBuffer.wrap(new byte[] { 'r','e', 's', 'p', 'o', 'n', 's', 'e' });

byte[] request=new byte[7];

System.out.println(readBuffer.get(request));

while (response.hasRemaining()) {

channel.write(response);

}

} else {

channel.close();

}

}

} catch (Throwable t) {

t.printStackTrace();

if (channel != null) {

channel.close();

}

}

}

public static void main(String[] args) {

NioServer nioServer = new NioServer();

nioServer.init();

nioServer.listen();

}

}

初始化方法主要做的事情包括分配读缓冲、开启一个ServerSocketChannel通道并设置为非阻塞、绑定8888端口、开启一个选择器Selector、将ServerSocketChannel对象以OP_ACCEPT作为感兴趣事件注册到选择器中。

监听方法主要做的事情是不断通过选择器select出感兴趣的事件,再将对应的key送到handleKey方法处理,分三种事件说明,①OP_ACCEPT事件,一个客户端连接连进来最开始会触发一个接收事件,此时要通过调用ServerSocketChannel对象的accept将客户端连接接收,并将接收到的客户端channel设置为非阻塞,最后将客户端channel以OP_READ事件注册到选择器中;②OP_READ事件,假如客户端连接写入“request”字符串,服务端选择器选择出该通道有字符串待读,从key中获取对应channel并执行read操作,这里会输出“request”字符串,然后向客户端输出“response”字符串;③OP_WRITE事件,这里为方便并没有注册写事件而是直接将字节串写回客户端,实际处理中可以这样:先尝试直接往通道写入,在网络阻塞时即循环写入数据写不了时则注册OP_WRITE事件避免线程阻塞,交给后面选择器select后再次进行写处理。

非阻塞模式提供了另外一种IO处理模型,把阻塞操作改成非阻塞操作,增加了程序编写的难度,但如果要写出高性能高并发的服务端服务则必须掌握NIO模式。

对java感兴趣的朋友可以交流下:

NIO模式例子