一、NIO简介
- NIO全称:Non-blocking IO 或 New IO,是非阻塞式的IO
- JDK版本:JDK1.4+
- 应用场景:高并发网络服务编程
二、编程模型
- 模型:对事物共性的抽象
- 编程模型:对编程共性的抽象
三、BIO网络模型
-
BIO网络模型介绍
从图中可以看出,一个线程到第5步的时候,会阻塞在那等待客户端的下次请求,每新增一个客户端,就会启动一个新的线程来处理这个客户端的请求,如果客户端量很大的话,就会造成服务器压力过大而崩溃。 -
BIO网络模型缺点
- 阻塞式IO模型
- 弹性伸缩能力差
- 多线程非常消耗资源
四、NIO网络模型
-
NIO网络模型介绍
相对于BIO,NIO的网络模型就要复杂的多,服务端提供一个单线程的Selector组件,它是一个事件注册监听器,负责监听管理注册到它上面的连接和事件,但是本身不负责处理客户端的业务逻辑。当它监听到指定的事件,就会启动相应的事件处理器去处理请求,事件处理器可以依次处理多个请求,处理完成之后,由事件处理器去响应客户端,Selector本身继续监听其他事件。 -
NIO模型的优点
- 非阻塞式IO模型
- 弹性伸缩能力强
- 单线程节约资源
- 原生NIO的缺点
- NIO类库和API比较复杂
- 可靠性能力补齐,工作量和难度都非常大
- Selector空轮询,导致CPU占用100%的bug还没有修复
五、具体代码实现
- 服务端代码
NioServer.java
package com.feonix;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* NIO服务器端
*/
public class NioServer {
/**
* 映射客户端channel
*/
private Map<String, SocketChannel> clientsMap = new HashMap<String, SocketChannel>();
public static void main(String[] args) {
NioServer nioServer = new NioServer();
try {
// 启动服务端
nioServer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 启动
*
* @throws IOException
*/
public void start() throws IOException {
// 1. 创建Selector
Selector selector = Selector.open();
// 2. 通过ServerSocket创建channel通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 3. 为channel通道绑定监听端口
serverSocketChannel.bind(new InetSocketAddress(8000));
// 4. 将channel设置为非阻塞模式
serverSocketChannel.configureBlocking(false);
// 5. 将channel注册到selector上,监听连接事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器端启动成功!");
// 6. 循环等待新接入的连接
for (; ; ) {
// 获取可用的channel数量
int readyChannels = selector.select();
// 屏蔽未就绪的连接,防止selector空轮询
if (readyChannels == 0) {
continue;
}
// 获取可用的channel集合
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys