select , poll ,epoll的基本使用

  |   0 评论   |   0 浏览

1. select

select系统调用的定义如下:

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

select系统调用时,向操作系统内核空间会拷贝3个fd_set,分别表示要监控读事件,写事件以及异常事件的fd集合,之后内核会对这些fd进行轮询,并将相应事件就绪的fd拷贝至对应的fd_set并在调用结束后将写好的fd_set返回至用户空间。

fd_set内部采用bitmask方式进行实现,因此打开的最大fd的数目受到一定的限制,由FD_SETSIZE常量表示,可以采用如下的API进行设置。

#include <sys/select.h>
 
void FD_ZERO(fdset* fds);         /* 将fdset置空 */
void FD_SET(int fd, fdset* fds);  /* fdset添加fd */
void FD_CLR(int fd, fdset* fds);  /* fdset删除fd */
int FD_ISSET(int fd, fdset* fds); /* 当前fd是否设置,若设置返回1,否则返回0*/

2. poll

poll系统调用的定义如下:

poll(struct pollfd fds[] , int nfds, int timeval);

poll系统调用的基本流程与select类似,区别是传入的是pollfd的数组而非fd_set(bitmask)。因此其数量不会受到限制,在每个pollfd结构体中,会标明当前监视的fd事件的bitmask也就是events,每次poll调用结束,内核会修改revents并将其返回。

由于poll传入的是一个数组而并非二进制掩码,所以其大小没有限制,使用时只需设置struct pollfd相应字段即可。

struct pollfd的结构如下所示:

struct pollfd{
     int fd;          /*  监听的文件描述符。 */
    short events;    /* 监听事件的bitmask,POLLIN,POLLOUT等  */
    short revents;   /* 返回事件的bitmask  */
}

3.epoll
epoll系统调用主要提供了3个API:

int epoll_create(int size);
int epoll_ctl(int epfd, int op , int fd , struct epoll_event *ev);
int epoll_wait(int epfd, strct epoll_event* ev,int maxevents ,int timeout);

3.1. epoll_create

epoll_create创建了一个epoll的实例,该实例的interest_list为空,调用返回一个代表该epoll实例的文件描述符,这个文件描述符不是用于IO,它代表了一个内核数据结构的句柄。
size参数指定了一个想要通过epoll实例来检查文件描述符的个数,这个参数并不代表着一个上限,而是告诉内核如何为内部结构划分初始大小。

3.2. epoll_ctl

epoll_ctl能够修改epoll实例对应的interest_list,包括向兴趣列表中添加,修改和删除fd的数据等。
op操作包括:EPOLL_CTL_ADD,EPOLL_CTL_MOD和EPOLL_CTL_DEL。
epoll_event的结构如下所示:

struct epoll_event {
     uint32_t events;       /* events is the bitmask of the epoll_event*/
     epoll_data_t data;     /* data is a union struct of the user_data */
}
typedef union epoll_data{
     void *ptr;
     int fd;
     uint32_t u32;
     uint64_t u64;
}

3.3. epoll_wait

epoll_wait返回epoll实例中就绪的文件描述符信息,返回值为当前就绪的fd数量,返回的event信息存储在evlist数组中,evlist的空间由用户自行申请,并指定最大返回的事件数量evlist。

timeout字段用来确定epoll_wait的阻塞行为。

  • timeout = 0 : 非阻塞。
  • timeout = -1 : 一直阻塞直到有event发生。
  • timeout > 0 : 函数将至多阻塞timeout毫秒,直到有event发生。

返回事件的种类存储在evlist的各个events中,使用bitmask表示。

常见events字段的bitmask值有以下几种:

  • EPOLLIN: 可读取非高优先级数据。
  • EPOLLPRI: 可读取高优先级数据。
  • EPOLLOUT: 普通数据可写。
  • EPOLLET: 采用边缘触发方式通知,只可作为epoll_ctl输入。
  • EPOLLERR: 表示event有错误发生,只可发生在epoll_wait返回。

标题:select , poll ,epoll的基本使用
作者:YaoCheng8667
地址:https://ycisme.xyz/articles/2020/04/01/1585707860765.html