NIO引入多路复用器实例
之前的NIO实例是为了本文做准备的,java底层即使用一个Selector(多路复用器)轮询来实现NIO,其基本的思路与前面的例子相同。
NIO 有三大核心组件: Channel(通道), Buffer(缓冲区),Selector(多路复用器)
1、channel 类似于流,每个 channel 对应一个 buffer缓冲区,buffer 底层就是个数组
2、channel 会注册到 selector 上,由 selector 根据 channel 读写事件的发生将其交由某个空闲的线程处理
3、NIO 的 Buffer 和 channel 都是既可以读也可以写
NIO引入多路复用器代码示例:
public class NioServer {
public static void main(String[] args) throws IOException {
//1、开启多路复用器
Selector selector = Selector.open();
//2、服务端socket
ServerSocketChannel socketChannel = ServerSocketChannel.open();
//3、绑定端口
socketChannel.bind(new InetSocketAddress(8897));
//4、设置非阻塞
socketChannel.configureBlocking(false);
//5、注册并设置监听的事件
socketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器启动成功");
//死循环
for (;;) {
System.out.println("此时没有客户端连接,select方法会阻塞轮询");
//阻塞,当selector中有事件发生时会解阻塞
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
//接受连接事件
if (key.isAcceptable()) {
ServerSocketChannel channel = (ServerSocketChannel) key.channel();
//接收客户端连接
SocketChannel clientSocket = channel.accept();
//客户端读事件非阻塞
clientSocket.configureBlocking(false);
clientSocket.register(selector, SelectionKey.OP_READ);
System.out.println("客户端连接成功");
}
//读事件
if (key.isReadable()) {
ByteBuffer buffer = ByteBuffer.allocate(128);
SocketChannel socketChannel1 = (SocketChannel) key.channel();
int len = socketChannel1.read(buffer);
if (len > 0) {
System.out.println("客户端传过来的数据是:" + new String(buffer.array()));
}
else if (len == -1) {
System.out.println("客户端未发送");
}
}
iterator.remove();
}
}
}
}
客户端:
public class NioClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1", 8897));
while (true) {
Scanner sc = new Scanner(System.in);
String msg = sc.next();
socket.getOutputStream().write(msg.getBytes());
}
}
}
当启动多个客户端时,服务端控制台结果:
没有客户端连接:
客户端1,连接未发送数据:
客户端发送数据:
可以多个客户端连接测试。
总结:同步非阻塞,服务器实现模式为一个线程可以处理多个请求(连接),客户端发送的连接请求都会注册到多路复用器selector上,多路复用 器轮询到连接有IO请求就进行处理。