NIO入门
NIO:客户端发送的连接请求都会注册到多路复用器selector上,多路复用 器轮询到连接有IO请求就进行处理
一、nio非阻塞代码
-
public static void main(String[] args) throws IOException {
-
//1、打开ServerSocketChannel
-
ServerSocketChannel ssc = ServerSocketChannel.open();
-
-
ssc.configureBlocking(false);
-
//2、绑定监听地址InetSocketAddress
-
ssc.socket().bind(new InetSocketAddress(9000));
-
//3、创建Selector,并启动线程
-
Selector selector = Selector.open();
-
//4、把ServerSocketChannel注册到Selector,监听
-
ssc.register(selector, SelectionKey.OP_ACCEPT);
-
-
while (true) {
-
int select = selector.select();
-
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
-
//5 Selector轮询指定的key
-
while (it.hasNext()) {
-
SelectionKey key = it.next();
-
it.remove();
-
handle(key);
-
}
-
}
-
}
-
-
private static void handle(SelectionKey key) throws IOException {
-
if (key.isAcceptable()) {
-
System.out.println("有客户端连接事件发生了。。");
-
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
-
//6、处理新的客户端接入
-
SocketChannel sc = ssc.accept();
-
//7、设置新的socket参数
-
sc.configureBlocking(false);
-
//8、将新接入的客户端连接注册到Reactor线程的多路复用器上,读取客户端发送的网络消息
-
sc.register(key.selector(), SelectionKey.OP_READ);
-
} else if (key.isReadable()) {
-
System.out.println("有客户端数据可读事件发生了。。");
-
SocketChannel sc = (SocketChannel) key.channel();
-
ByteBuffer buffer = ByteBuffer.allocate(1024);
-
//9、异步读取客户端请求消息到缓冲区
-
int len = sc.read(buffer);
-
if (len != -1) {
-
System.out.println("读取到客户端发送的数据:" new String(buffer.array(), 0, len));
-
}
-
ByteBuffer bufferToWrite = ByteBuffer.wrap("HelloClient".getBytes());
-
//10 将消息异步发送给客户端
-
sc.write(bufferToWrite);
-
key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
-
} else if (key.isWritable()) {
-
SocketChannel sc = (SocketChannel) key.channel();
-
System.out.println("write事件");
-
key.interestOps(SelectionKey.OP_READ);
-
}
-
}
打开cmd窗口,输入以下命令,实现客户端和服务端交互:
-
telnet localhost 9000
-
ctrl ]
-
send 123
二、nio服务端代码时序图
上面服务端代码启动时序图:
三、核心代码底层调用
-
1 Selector.open() //创建多路复用器 (底层调用的epoll_create)
-
2 socketChannel.register() //将channel注册到多路复用器上 (底层调用的 epoll_ctl)
-
3 selector.select() //阻塞等待需要处理的事件发生 (底层调用的epoll_wait)
几个核心函数
int epoll_create(int size);
1、创建一个epoll实例,并返回一个非负数作为文件描述符,size代表表可能会容纳size个描述符
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
2、使用文件描述符epfd引用的epoll实例,对目标文件描述符fd执行op操作。
epfd: epoll对应的文件描述符 fd: socket对应的文件描述符 参数op有以下几个值: EPOLL_CTL_ADD:注册新的fd到epfd中,并关联事件event; EPOLL_CTL_MOD:修改已经注册的fd的监听事件; EPOLL_CTL_DEL:从epfd中移除fd,并且忽略掉绑定的event,这时event可以为null; events有很多可选值,这里只举例最常见的几个: EPOLLIN :表示对应的文件描述符是可读的; EPOLLOUT:表示对应的文件描述符是可写的; EPOLLERR:表示对应的文件描述符发生了错误;
1 int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
3、等待文件描述符epfd上的事件。
epfd: Epoll对应的文件描述符,
events: 调用者所有可用事件的集合,
maxevents: 最多等到多少个事件就返回, timeout: 超时时间。
总结:nio就是通过操作系统内核函数创建socket,获取文件描述符,再创建一个Selector ,获取Epoll文件描述符,将socket文件描述符绑定到Selector的文件描述符上,进行事件的异步通知;就实现了使用一条线程,并且不需要太多的无效的遍历 ,将事件处理交给操作系统内核,事件通知无需遍历,大大提高了效率。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfhfhib
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13