1.select实现
//1.创建表
fd_set readfds;
//清空表,局部变量,内部为随机值
FD_ZERO(&readfds);
//2.将关心的文件描述符添加到表中
FD_SET(0,&readfds);
//3.调用select函数检测事件
select(nfds;&readfds,NULL,NULL,NULL);
//功能:监测那个或者那些文件描述符产生事件
//nfds:检测的文件描述符个数
//readfds: 读事件集合; //读(用的多)
//writefds: 写事件集合; //NULL表示不关心
//exceptfds:异常事件集合;
//timeout:超时检测 1
//4.当文件描述符中的一个或者多个已经准备好进行I/O操作时候该函数才返回,结束阻塞
//5.判断哪一个文件或者那些文件描述符产生了事件(IO操作);
FD_ISSET(fd,&eadfds);
//6.做对应的逻辑处理;
IO多路复用特点
1.一个进程做多只能监听1024个文件描述符
2.select被唤醒后需要轮询一遍驱动的poll函数,效率比较低(消耗CPU资源);
3.select每次会清空表,每次都需要拷贝用户空间的表到内核空间,效率低
poll实现
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参p数:
struct pollfd *fds
关心的文件描述符数组struct pollfd fds[N];
nfds:个数
timeout: 超时检测
毫秒级的:如果填1000,1秒
如果-1,阻塞
struct pollfd {
int fd; /* 检测的文件描述符 */
short events; /* 检测事件 */
short revents; /* 调用poll函数返回填充的事件,poll函数一旦返回,将对应事件自动填充结构体这个成员。只需要判断这个成员的值就可以确定是否产生事件 */
};
事件: POLLIN :读事件
POLLOUT : 写事件
POLLERR:异常事件
poll实现IO多路复用的特点
1. 优化文件描述符个数的限制;(根据poll函数第一个函数的参数来定,如果监听的事件为1个,则结构体数组元素个数为1,如果想监听100个,那么这个结构体数组的元素个数就为100,由程序员自己来决定)
2. poll被唤醒之后需要重新轮询一遍驱动的poll函数,效率比较低
3. poll不需要重新构造文件描述符表,只需要从用户空间向内核空间拷贝一次数据即可
epoll实现
#include <sys/epoll.h>
int epoll_create(int size);
功能:创建红黑树根节点
参数:size:不作为实际意义值 >0 即可
返回值:成功时返回epoll文件描述符,失败时返回-1。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:控制epoll属性
epfd:epoll_create函数的返回句柄。
op:表示动作类型。有三个宏 来表示:
EPOLL_CTL_ADD:注册新的fd到epfd中
EPOLL_CTL_MOD:修改已注册fd的监听事件
EPOLL_CTL_DEL:从epfd中删除一个fd
Fd:需要监听的fd。
event:告诉内核需要监听什么事件
EPOLLIN:表示对应文件描述符可读
EPOLLOUT:可写
EPOLLPRI:有紧急数据可读;
EPOLLERR:错误;
EPOLLHUP:被挂断;
EPOLLET:触发方式,边缘触发;(默认使用边缘触发)
ET模式:表示状态的变化;
返回值:成功时返回0,失败时返回-1
typedef union epoll_data {
void* ptr;(无效)
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; / * Epoll事件* /
epoll_data_t data; / *用户数据变量* /
};
//等待事件到来
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
功能:等待事件的产生,类似于select的用法
epfd:句柄;
events:用来保存从内核得到事件的集合;
maxevents:表示每次能处理事件最大个数;
timeout:超时时间,毫秒,0立即返回,-1阻塞
成功时返回发生事件的文件描述个数,失败时返回-1
epoll实现IO多路复用的特点
•监听的最大的文件描述符没有个数限制(理论上,取决与你自己的系统)
•异步I/O,Epoll当有事件产生被唤醒之后,文件描述符主动调用callback(回调函数)函数直接拿到唤醒的文件描述符,不需要轮询,效率高
•epoll不需要重新构造文件描述符表,只需要从用户空间向内核空间拷贝一次数据即可.