NIO编程模型以及核心组件简介 多路复用示例(五)
!(data/attachment/forum/202210/27/161654ybj4s6siz4eea6s3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")不管是多Reactor还是多线程模式,只是在基本Reactor模式下的扩展,基本原型是不变的。
NIO的编程模型,也是类似如此。
### 示例
引入多路复用的NIO示例程序。
```java
https://gitee.com/crazybytex/java-code-fragment/blob/master/src/main/java/com/crazybytex/fragment/nio/NioServer.java
```
```java
package com.crazybytex.fragment.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
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;
import java.util.Set;
/**
* @Author 本文作者 程序员潇然 疯狂的字节X https://www.crazybytex.com/
* @Date 2022/10/27 16:18
* @Description
**/
public class NioServer {
public static void main(String[] args) throws IOException, InterruptedException {
// 创建NIO ServerSocketChannel
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.socket().bind(new InetSocketAddress(9000));
// 设置ServerSocketChannel为非阻塞
serverSocket.configureBlocking(false);
// 打开Selector处理Channel,即创建epoll
Selector selector = Selector.open();
// 把ServerSocketChannel注册到selector上,并且selector对客户端accept连接操作感兴趣
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务启动成功");
while (true) {
// 阻塞等待需要处理的事件发生
selector.select();
// 获取selector中注册的全部事件的 SelectionKey 实例
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
// 遍历SelectionKey对事件进行处理
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
// 如果是OP_ACCEPT事件,则进行连接获取和事件注册
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = server.accept();
socketChannel.configureBlocking(false);
// 这里只注册了读事件,如果需要给客户端发送数据可以注册写事件
socketChannel.register(selector, SelectionKey.OP_READ);
System.out.println("客户端连接成功");
// 如果是OP_READ事件,则进行读取和打印
} else if (key.isReadable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(128);
int len = socketChannel.read(byteBuffer);
// 如果有数据,把数据打印出来
if (len > 0) {
System.out.println("接收到消息:" + new String(byteBuffer.array()));
// 如果客户端断开连接,关闭Socket
} else if (len == -1) {
System.out.println("客户端断开连接");
socketChannel.close();
}
}
//从事件集合里删除本次处理的key,防止下次select重复处理
iterator.remove();
}
}
}
}
```
### 流程
!(data/attachment/forum/202210/27/170518xa67xylgcjjcz699.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")
### 主要概念对比
!(data/attachment/forum/202210/27/171409sf3nsx2xktn2l3xt.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")
### NIO模型与交互
java的NIO可以认为是Reactor模式的一个实现,提供了一个编程模型
!(data/attachment/forum/202210/27/173434vatrhuqcb9ktr4mu.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")
### NIO核心组件
!(data/attachment/forum/202210/27/200041ra1c6xzap6sskm5m.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")
NIO 有三大核心组件: Channel(通道), Buffer(缓冲区),Selector(多路复用器)
1、channel 类似于流,每个 channel 对应一个 buffer缓冲区,buffer 底层就是个数组
2、channel 会注册到 selector 上,由 selector 根据 channel 读写等事件的发生将其交由某个空闲的线程处理
3、NIO 的 Buffer 和 channel 都是既可以读也可以写
参照上面的流程,客户端通过buffer与channel交互,Selector通过事件机制与channel进行交互,进而达到客户端与Server的交互通信。
网络通信的编程接口仍旧是Socket,他的实现基础在NIO里面是Channel
!(data/attachment/forum/202210/31/161324i15jz77vzj1qoaat.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")
Channel用于源和目的地的连接,是一个双向通道。
而且,必须经过Buffer,不能直接对Channel进行数据的读写,可以查看类图层次,以及对应的read或者write方法的参数得到证明。
### 小结
NIO就是Java 对Reactor模式的实现,提供了 Buffer、Channel、Selector等核心组件。
通过Channel进行连接操作管理,通过Buffer进行数据读写,通过Selector进行事件绑定回调等。
!(data/attachment/forum/202206/16/141330jha7st9soow8772i.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "common_log.png")
`转载务必注明出处:程序员潇然,疯狂的字节X,https://crazybytex.com/thread-206-1-1.html `
页:
[1]