欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

select、poll、epoll用法区别与联系

程序员文章站 2022-06-14 09:02:16
...

一、多路IO转接原理图

select、poll、epoll用法区别与联系

二、多路IO转接select

1.select介绍

Select监听的文件描述符受限于FD_SETSIZE,一般为1024,单纯改变进程打开的文件描述个数并不能改变select监听的文件描述符个数,由于select采用的是轮询机制,故而如果客户端过多的话,效率会比较很低。

2.select控制原语

函数原型:

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

参数1: int nfds为要监听的最大问价描述符+1
参数2: 读 文件描述符集合 传入、传出
参数3: 写 文件描述符集合 NULL 传入、传出
参数4: 异常 文件描述符集合 NULL 传入、传出
参数5: NULL——永久等; > 0 —— 等待指定时间。

fd_set: 文件描述符集合 fd_set fds; 位图

void FD_ZERO(fd_set *set);              清空监听集合
void FD_SET(int fd, fd_set *set);       将fd添加到监听集合里
void FD_CLR(int fd, fd_set *set);       将fd 从 监听集合中 删除
 int  FD_ISSET(int fd, fd_set *set);    判断 fd 是否在  监听的集合

返回值:所有监听文件描述符中, 满足条件的“总”个数。 FD_ISSET( , readfds) –> 1 真

FD_ISSET(, writefds) --> 1 

3.使用select的注意事项及适用场景

注意事项

监听文件描述符上限 1024,如果需要改变监听的文件描述,那么需要改内核,重新编译;当客户端访问量很大,由于轮询机制,效率会降低;不能使用sleep相关类似事件。

适用场景

智能家居

三、多路IO转接poll模型

1.poll介绍

poll突破1024文件描述上限,实现了 传入、传出参数分离。但它所处的位置十分尴尬,处于select和epoll之间,很少有人会直接用它的。

2.poll控制原语

函数原型:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

pollfd结构体:

struct pollfd
{
   int   fd;        监听的文件描述符
   short events;    //POLLIN、POLLOUT、POLLERR
   short revents;   poll返回时满足该条件的revents == events;
 };

参数1: 监听的文件描述符所在结构体 struct pollfd 数组。
参数2: 数组元素个数。
参数3: milliseconds 毫秒。
返回值:跟select 一样。

四、多路IO转接epoll模型

1.epoll简介

epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符集合来传递结果而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。目前epell是linux大规模并发网络程序中的热门首选模型。epoll除了提供select/poll那种IO事件的电平触发(Level Triggered)外,还提供了边沿触发(EdgeTriggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率

2.epoll的控制原语

函数原型1:

int epoll_create(int size); 创建一个 epoll 秘书。      

参数:size监听上限数
返回值: 文件描述符: epfd (句柄 — 红黑树)

函数原型2:

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)       

参数1: epfd create的返回值(红黑树)
参数2: op

EPOLL_CTL_ADD (注册新的fd到epfd),
EPOLL_CTL_MOD (修改已经注册的fd的监听事件),
EPOLL_CTL_DEL (从epfd删除一个fd);

参数3:fd 监听的文件描述符
参数4:event 结构体的地址(&event)

struct epoll_event
{
    uint32_t  events;  //EPOLLIN、EPOLLOUT、EPOLLERR      
    epoll_data_t data; //用户数据
};

typedef union epoll_data 
{  
     void        *ptr;
     int          fd;       监听的文件描述符。
     uint32_t     u32;
     uint64_t     u64;
 } epoll_data_t;

返回值: 成功0 失败-1

函数原型3:

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)  阻塞监听

参数1: epfd 红黑树的根
参数2: events 【数组】 传出参数。 内部 struct epoll_event 类的结构体。
参数3: 数组的容量
参数4: 等待毫秒数
返回值:满足条件的文件描述符总个数

3.epoll-ET和 epoll-LT

LT(水平触发或电平触发): 缓冲区 如果有没读完的数据,epoll_wait 也触发。
ET(边缘触发):缓冲区 如果有没读完的数据,epoll_wait 不触发。 等下一次客户端再发送数据的时候,触发。

4.epoll适用场景

效率和并发量