一、介绍
多路IO复用,是通过系统底层对描述符事件的检测,通过描述符集合返回,通过描述符集合实现对单一句柄操作
多路IO复用有三种:
(1)select
(2)poll
(3)epoll
对比:
特点 | select | poll | epoll |
句柄个数 | 32位 <1024 64位 <2048 | 无限制 | 无限制 |
平台 | POSIX | Linux | Linux |
监听方式 | 轮询 | 轮询 | 事件通知 |
触发方式 | 水平触发 | 水平触发 | 边缘 ET 水平 LT |
效率 (fd数量上升) | 线性下降 | 线性下降 | 无变化 |
消息传递方式 | 内核拷贝至用户空间 | 内核拷贝至用户空间 | 内核与用户空间共用一块内存 |
二、函数接口
1、select
头文件<sys/select.h>
1、阻塞检测
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
返回值:
超时:0
成功:返回触发个数
失败:-1
参数:
nfds:描述符上限,即所有文件描述符的最大值加1
readfds 只读描述符集
writefds 只写描述符集
exceptfds 异常描述符集
timeout:检测超时,NULL表示一直不超时
2、添加描述符
void FD_SET(int fd, fd_set *set);
3、删除描述符
void FD_CLR(int fd, fd_set *set);
4、判断描述符是否在集合
int FD_ISSET(int fd, fd_set *set);
5、清空集合
void FD_ZERO(fd_set *set);
2、poll
头文件<poll.h>
1、阻塞等待
int poll(struct poll_fd *fds, nfds_t nfds, int timeout);
返回值:
成功:返回描述符集合个数
超时:0
失败:-1
参数:
fds:描述符集合数组
nfds:fds数组长度
timeout:超时,单位ms
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
3、epoll
头文件<sys/epoll.h>
1、创建
int epoll_create(int size);
int epoll_create1(int flags);
返回值:
成功:返回epoll描述符(句柄)
失败:-1
参数:
size:告诉内核一个管理句柄的个数估值,内核版本2.6.8之后,该参数被忽略
flags:设置为0与epoll_create无差别
2、控制
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
返回值:
成功:0
失败:-1或者错误号
参数:
epfd:epoll的描述符
op:选项
EPOLL_CTL_ADD:添加
EPOLL_CTL_MOD:修改
EPOLL_CTL_DEL:删除
fd:被操作的描述符
event:描述符fd的事件
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
events:
EPOLLIN:读触发
EPOLLOUT:写触法
EPOLLET:边缘触发,默认是水平触发
EPOLLRDHUP:流套接字close或shutdown写,在ET模式比较有用
EPOLLERR:出错
EPOLLPRI:紧急数据可读
EPOLLHUP:挂起,EPOLLERR和EPOLLHUP始终由epoll_wait监听,不需要用户设置
3、事件等待
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask);
返回值:
成功:返回触发句柄个数,0为超时
失败:-1或者错误号
参数:
epfd:epoll句柄
events:触发句柄的事件载体,通常为一个struct epoll_event数组
maxevents:处理最大个数
timeout:超时时间
sigmask:信号屏蔽掩码
以下两种操作等价
(操作1)
ready = epoll_pwait(epfd, &events, maxevents, timeout, &sigmask);
(操作2)
sigset_t origmask;
pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
ready = epoll_wait(epfd, &events, maxevents, timeout);
pthread_sigmask(SIG_SETMASK, &origmask, NULL);
sigmask=NULL时,两函数等价
3、IO设置(阻塞与非阻塞)
头文件
<fcntl.h>
<unistd.h>
1、设置函数
int fcntl(int fd, int cmd, ... /* arg */ );
返回值:
失败:-1或者错误号
新的描述符 cmd=F_DUPFD
描述符标志 cmd=F_GETFD
文件状态 cmd=F_GETFL
文件描述符保存的类型 cmd=F_GETLEASE
描述符的所有者 cmd=F_GETOWN
管道的容量
cmd=F_GETPIPE_SZ
cmd=F_SETPIPE_SZ
参数:
fd:文件描述符
cmd:
复制一个描述符
F_DUPFD
F_DUPFD_CLOEXEC
描述符状态
F_GETFD 获取
F_SETFD 设置
文件状态
F_GETFL 获取
F_SETFL 设置
设置为非阻塞步骤:
int old_flag = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, old_flag | O_NONBLOCK);
三、示例
epoll Demo:https://download.csdn.net/download/liutit/85077598