select,poll,epoll是io多路复用技术;(阻塞+不考虑线程,进程)
应用场景:标准输入,套接字等都可以看做I/O的一路,当任何一路上的io事件发生时,内核移交控制权给应用程序进行io事件处理;
io事件诸如:标准输入文件描述符准备好可以读;监听套接字准备好,新的连接已经建立成功;已连接套接字准备好可以写;如果io事件等待超过10秒,发生了超时事件。
select:
维护三个描述符集合:读描述符集合,写描述符结合,异常描述符集合。
循环过程中初始化待测试的描述符集合,调用select,当待测试的描述符上有io事件发生时,解除阻塞,调用应用程序处理io事件。
缺点:支持的描述符个数有限。
poll:
int poll(struct pollfd*fds,unsigned long nfds,int timeout)
若有就绪描述符则返回其数目,超时返回0,出错返回-1
struct pollfd{
int fd;//文件描述符
short events;//事件性质,POLLIN表示读事件,POLLOUT表示写事件
short revents;//poll检测后的返回值
};
timout为-1,调用者进程被阻塞,直到内核io事件的分发。fds为带有事件属性的描述符集合,将监听套接字加入fds,表示期望内核检测监听套接字的连接建立完成事件。当有io事件触发时,遍历所有的文件描述符。
epoll:
随着文件描述符增多,epoll的性能远远高于select,poll。添加两个机制:边缘触发和水平触发。epoll较poll性能提升的一点在于epoll只遍历触发io事件的就绪文件描述符。
int epoll_create(int size)//创建epoll实例;
int epoll_ctl(int epfd,int op,int fd,struct epoll_event*event);//向epoll实例里添加 或删除监控文件描述符。
epfd :epoll实例描述符;
op:标识删除还是增加事件;
fd:文件描述符;
event:带有可读或者可写等属性的事件
typedef union epoll_data{
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
}epoll_data_t;
struct epoll_event{
uint32_t events;
epoll_data_t data;
};
int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);
//类似select或者poll用于内核io事件分发,若无io事件,则调用者阻塞。返回值为io事件个数,无io事件返回0;
epfd:epoll实例描述符;
events待调用的事件集合;
tiimeout设置为-1,表示不超时,设置为0,表示没有io事件发生,立即返回。
创建epoll实例后,将监听套接字对应的io事件加入到epoll,这样有新的连接的时候,会被感知到;当监听套接字被触发时,再把新的socket注册到epoll中;
边缘触发和条件触发的适用情况:
条件触发(LT):只要满足条件,比如有数据可读,就一直不断地把这个事件传递给用户,比如listen_fd加入epoll时候,标识为LT;大块数据远远大于缓存时。
边缘触发(ET):只有第一次满足条件的时候才触发。