IO模型和Selector详解

IO模型

BIO

同步阻塞模型,一个客户端连接对应一个处理线程

缺点
1、IO代码里read操作是阻塞操作,如果连接不做数据读写操作会导致线程阻塞,浪费资源
2、如果线程很多,会导致服务器线程太多,压力太大,比如C10K问题

应用场景
BIO 方式适用于连接数目比较小且固定的架构, 这种方式对服务器资源要求比较高, 但程序简单易理解。

NIO

同步非阻塞,服务器实现模式为一个线程可以处理多个请求(连接),客户端发送的连接请求都会注册到多路复用器selector上,多路复用器轮询到连接有IO请求就进行处理。
应用场景
NIO方式适用于连接数目多且连接比较短(轻操作) 的架构, 比如聊天服务器, 弹幕系统, 服务器间通讯,编程比较复杂

NIO 相关组件
Channel(通道), Buffer(缓冲区),Selector(多路复用器)
1、channel 类似于流,每个channel 对应一个buffer缓冲区,buffer底层就是个数组
2、channel 会注册到 selector 上,由 selector 根据 channel 读写事件的发生将其交由某个空闲的线程处理
3、NIO 的 Buffer 和 channel 都是既可以读也可以写

以服务端角度理解NIO多路复用器
1、创建ServerSocketChannel并绑定端口(如9000端口)
2、 Selector.open() 创建多路复用器Selector
3、将服务端的ServerSocketChannel注册到selector上,类型为连接事件
4、使用selector.select()阻塞等待客户端事件
5、若客户端有连接过来,则通过selector.selectedKeys获取对应的selector实例
5.1、若为连接事件,则selector实例得到ServerSocketChannel,服务端channel使用.accept()建立连接并得到对应客户端的SocketChannel;给客户端SocketChannel注册读事件
5.2、若为读事件,则使用SocketChannel从buffer缓冲区中读取客户端发送的数据

每个客户端在服务端都有一个SocketChannel,所有的读写事件都由各自的SocketChannel处理

Selector底层原理

Selector是基于epoll的事件通知方式调用的,当有IO事件就绪,系统注册的回调函数就会被调用

Selector.open()

epoll_create:调用linux内核函数epfd = epoll_create(),创建epoll对象,并返回epoll对象的文件描述符(文件描述符其实就是对象在操作系统上的索引)
socketChannel.register(selector, SelectionKey.OP_READ);将socketChannel的fd(文件描述符)添加到epoll对象的pollWrapper集合中

Selector.select()

epoll_ctl:内核函数,将我们的epoll对象和socketChannel关联起来,并将事件注册到epoll实例上,有事件该方法就能感知到,然后将事件添加到epoll内部的就绪事件列表rdlist中,该rdlist其实就是我们每次while循环要处理的事件(在操作系统层面,服务到接受到客户端数据后,就会产生事件,会进行系统中断,然后将响应的事件放到rdlist列表中)。
epoll_wait:内核函数,等待epfd上的事件,看就绪事件列表rdlist中有没有事件,没有就阻塞,有则获取事件集合,即通过selector.selectedKeys()就能拿到对应事件实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值