1、创建文件描述符集合 fd_set
2、添加文件描述符到集合中 int FD_ISSET(int fd, fd_set *set);
3、通知内核开始监测 select
4、内核返回的结果(两个结果,1、是那种类型得文件),做对应得操作(对IO读、写操作)
(1)select()函数接口
#include
#include
#include
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
功能:检查多了IO
参数:
nifds:最大文件描述符+1(方便内核查找)
readfds 关注读事件的文件描述符集合
writefds:关注的写事件的文件描述符集合
exceptfds:其他异常文件描述符的集合
timeout:超时时间,等到了这个时间到了,就不在死等了,如果不设置超时时间,则设置为NULL
代参宏
void FD_CLR(int fd, fd_set *set);把这个套接字从这个集合中删除掉
int FD_ISSET(int fd, fd_set *set);判断对应位有没有设置为1
void FD_SET(int fd, fd_set *set);要有多个设置文件,则每个调用一遍
void FD_ZERO(fd_set *set);
返回值
成功:返回到达事件的个数(因为IO端口事件可能同时到达)
失败L:-1设置了超时时间:超时时间到达但没有时间,返回0
epoll:
1、创建文件描述符集合:(在内核中)
函数接口
#include
int epoll_create(int size);告诉内核大概放多少个文件描述符 返回值: 成功:返回一个文件描述符(集合句柄) 失败:-1
2、添加文件描述符到集合
#include
int epoll_ctl(int epfd, int op, int fd, struct epoll_event*event); 参数: epfd :文件描述符集合句柄 op : EPOLL_CTL_ADD:向集合中添加文件描述符 EPOLL_CTL_MOD:修改集合 EPOLL_CTL_DEL:删除文件描述符 EPOLL_CTL_DEL(集合,对象) 删除的时候不需要关注他具体做什么操作 fd:文件描述符 struct epoll_event *event: 对这个文件描述符所对应的事件做什么操作 struct epoll_event { uint32_t events; /* Epoll events */ EPOLLIN 读操作 EPOLLOUT 写操作 epoll_data_t data; /* User data variable */ typedef union epoll_data { void *ptr; int fd;//设置读事件或者写事件的关注的文件描述符 uint32_t u32; uint64_t u64; } epoll_data_t; 返回值 成功:返回0 失败:返回-1或者errno
3、通知内核开始监测
#include
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout); 功能:监测IO事件 参数: epfd:文件描述符集合句柄 events:保存最终的结果,的数组的首地址(a) maxevents: 监测时事件的个数 timeout :超时时间 -1:设置超时时间 返回值: 成功:返回到达事件的个数 失败:返回-1 超时时间结束:0
1.select监听文件描述符最大个数为1024(数组)时间复杂度为0(n)
2.select监听的文件描述符集合在用户层,需要应用层和内核层互相传递数据
3.select需要循环遍历一次才能找到产生的事件
4.select只能工作在水平触发模式(低速模式)无法工作在边沿触发模式(高速模式)
1.监测文件描述符不受上限限制(链表)O(n)
2.监听的文件描述符集合在用户层,需要内核层向用户层传递数据
3.需要循环遍历一次才能找到产生的事件
4.只能工作在水平触发模式(低速模式)无法工作在边沿触发模式(高速模式)
IO多路复用只用一个进程
耗时比较大;不适合处理比较耗时的任务
应用场景
1、构建并发服务器,用来检测多个客户端套接字
2、使用io多路复用监测多个IO所对应的通信(如:网络、串口、can)
3、在阻塞io中,进行超时监测
实际上是在一个进程中监测多个io的读和写