IO模型---IO多路复用

一、IO多路复用简介

允许单个线程或者进程管理多个网络连接或者文件描述符

可以通过以下几种机制实现:

  1. select(表,本质就是一个结构体,成员只有一个数组)
    ① select监听的最大文件描述符个数是1024
    ② select会有清空表的过程,需要反复构造表,反复拷贝表,效率比较低
    ③ select对应的进程从休眠态被唤醒后,需要再次遍历文件描述符表找到就绪的文件描述符,效率比较低
  2. poll(链表)
    ① poll监听的文件描述符没有个数限制
    ② poll没有清空表的过程,不需要反复构造表,反复拷贝表,效率比较高
    ③ poll对应的进程从休眠态被唤醒后,需要再次遍历文件描述符表,效率比较低
  3. epoll(红黑树+双向链表:红黑树保存要监听的文件描述符,双向链表保存就绪的文件描述符)
    ① epoll监听的文件描述符没有个数限制
    ② epoll没有清空表的过程,不需要反复构造表,反复拷贝表,效率比较高
    ③ epoll对应的进程从休眠态被唤醒后,将就绪的文件描述符直接放到双向链表中,不需要再次遍历文件描述符表,能直接获得就绪的文件描述符,效率比较高

二、应用层相关API

(一)select

#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
功能:
	允许一个进程或线程管理多个文件描述符
参数:
	nfds:监听的文件描述符数量,即最大的文件描述符+1
	readfds:监听读表; 没有可以传NULL
	writefds:监听写表; 没有可以传NULL
	exceptfds:监听其他表; 没有可以传NULL
	timeout:超时时间; NULL表示会一直阻塞,直到有文件描述符就绪
返回值:
	成功返回三个集合一共就绪的文件描述符数量
	失败返回-1,重置错误码
	
//判断fd是否存在于表中
int  FD_ISSET(int fd, fd_set *set);
//向表中添加成员
void FD_SET(int fd, fd_set *set);
//删除表中的成员
void FD_CLR(int fd, fd_set *set);
//清空表
void FD_ZERO(fd_set *set);

补充:fd_set
该表本质就是一个结构体,结构体中只有一个unsigned long类型(4个字节,即32位)的数组成员,该数组有32个元素,即4*8*32=1024

  • 注:进程会记录自己打开的文件描述符个数,每个进程维护自己的fd,进程与进程之间的fd互不影响

(二)poll

 #include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
功能:
	允许程序同时监视多个文件描述符,查看其是否发生读、写或者错误等事件
参数:
	fds:指向pollfd结构数组的指针。每个pollfd结构代表一个要监视的文件描述符及其感兴趣的事件。
	nfds:监视的文件描述符数量,即最大的文件描述符加1
	timeout:超时时间
返回值:
	成功返回revents为非0的结构体数量
	超时没有就绪文件描述符,返回0
	失败返回-1,重置错误码
	
struct pollfd {
     
    int fd;         // 文件描述符  
    short events;   // 感兴趣的事件  
    short revents;  // 返回的事件  
};
成员:
	fd:要监视的文件描述符。
	events:通过位掩码指定的感兴趣的事件类型,如POLLIN(有数据可读)、POLLOUT(可以写入数据)等。
	revents:在调用poll后,由系统填充,表示实际发生的事件。
	nfds:fds数组中的元素数量,即要监视的文件描述符的数量。这个值通常是fds数组中最后一个元素的索引加1。
	timeout:指定等待事件的超时时间(毫秒)。
		如果timeout为-1,则poll会无限期地等待,直到某个事件发生。
		如果timeout为0,则poll会立即返回,不阻塞。
		如果timeout为正数,则poll会等待指定的毫秒数,如果在这段时间内没有事件发生,则返回

(三)epoll

更适用于高并发场景,epoll使用红黑树作为底层数据结构来维护注册的文件描述符集合,实现高效的检索和管理

#include <sys/epoll.h>
int epoll_create(int size);
功能:
	创建一个epoll实例
参数:
	@size:这是一个提示性的参数,表示epoll实例可以监视的文件描述符的数量上限。Linux 2.6.8及以后的版本中,这个参数被忽略,但仍然需要传递一个大于0的值。
返回值:
	成功返回epfd;
	失败返回-1,重置错误码
备注:
	这个函数本质就是创建一个红黑树,用户通过epfd拿到红黑树,这个epfd也会占用一个文件描述符fd


int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:
	epoll的控制操作
参数:
	@epfd:由epoll_create返回的文件描述符,表示epoll实例
	@op:操作方式
	 	EPOLL_CTL_ADD	添加
       	EPOLL_CTL_MOD	修改
       	EPOLL_CTL_DEL	删除
	@fd:被操作的文件描述符
	@event:事件结构体,包含事件类型
		struct epoll_event{
   
			uin32_t	events;  //events字段表示注册的事件类型(如EPOLLIN、EPOLLOUT等)
			epoll_data_t data; //data字段用于存储用户数据
		}
返回值:
	成功返回0;
	失败返回-1,置位错误码


int epoll_wait(int epfd, struct epoll_event *revents, int maxevents, int timeout);
功能:
	阻塞等待文件描述符就绪
参数:
	@epfd		epoll实例
	@revents	用于存放事件信息的数组,每个数组元素都是epoll_event类型的结构体。这个数组用于接收就绪的文件描述符及其对应的事件信息。
	@maxevents	events数组的大小,即最多可以等待多少个事件
	@timeout	超时时间
		= 0	:立即返回
		> 0	:毫秒超时
		=-1	:忽略超时,永久阻塞,直到有fd就绪
返回值:
	成功,返回就绪的文件描述符的个数;
	超时,返回0,代表超时,没有文件描述符就绪
	失败,返回-1,重置错误码

三、内核中IO多路复用的实现机制

US:
---
 select(fd2 + 1, &rfds, NULL, NULL, NULL)
-----------------------------------------------------------
KS: VFS: 
---
进入到内核层之后会调用到syscall函数,进行宏定义替换后会得到sys_select函数

	long sys_select(int n, fd_set __user * inp, fd_set __user * outp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值