网络编程中select、poll与epoll详解

本文详细介绍了网络编程中的I/O复用模型,重点讲解了select、poll和epoll的区别与特性。select受限于fd_set大小,poll克服了这一限制但仍有遍历问题,而epoll利用红黑树高效管理文件描述符,采用回调机制避免轮询,支持边缘触发和水平触发,提供更高效的事件处理方式。
摘要由CSDN通过智能技术生成

网络编程中select、poll与epoll详解

​ 在C/S中,存在多种I/O模型(详见历史文章—C/S编程中常见的I/O模型介绍)。select、poll与epoll用于其中的I/O复用模型中,其读写是同步阻塞的。相比普通的read、write操作,可以检测多个描述符。

1.select函数

1.1 函数简介

​ select函数原型:

#include <sys/select.h>
#include <sys/time.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
          const struct timeval *timeout);
// 返回:表示此时有多少个监控的描述符就绪,若超时则为0,出错为-1。

参数说明:

​ maxfdp1:感兴趣的描述符中,最大的数值加1,所以名字是max fd plus 1。

​ readset/writeset/exceptset:指定内核感兴趣的读、写和异常的描述符,若对某些参数不感兴趣就设置为空指针NULL。

​ timeout:时间结构体,指定select函数阻塞的时间,若超过该时间,则select返回0。

1.2 特性

​ · 当执行select函数时,系统会将select中设定的fd_set等内容复制到内核空间中,内核将进行监听设定的感兴趣文件描述符;

​ · 当select函数返回时,系统会将就绪描述符写入readset,writeset和exceptset中,并将其拷贝到用户空间中,并返回就绪描述符个数;

​ 因此,每次调用都会来回拷贝fd_set中的内容,这对于高效网络编程来说无疑是致命的。同时,用户在处理返回的就绪描述符时,需要遍历整个监听的文件描述符集合fd_set,效率低下。

​ 注意:select函数受fd_set的大小限制,可以通过cat /proc/sys/fs/file-max 进行查看,32位最多能监听的fd为1024个,64位最多监听2048个。

2.poll函数

2.1 函数简介

poll函数原型:

int poll(struct pollfd* fds, int nfds, int timeout);
/*
struct pollfd{
	int fd;        // 感兴趣fd
	short events;  // 监听事件
	short revents; // 就绪事件
};
*/
// 返回:表示此时有多少个监控的描述符就绪,若超时则为0,出错为-1。

参数介绍:

​ fds:一个监听文件描述符数组的首地址,可以是pollfd数组名。

​ nfds:监听文件描述符数量。

​ timeout:超时时间设置,其取值如下:

timeout值说明
INTTM永远等待
0立即返回,不阻塞进程
>0等待指定数目的毫秒数

2.2 特性

poll函数与select原理相似,都需要来回拷贝全部监听的文件描述符。不同的是:

​ · poll函数采用链表的方式替代原来select中fd_set结构,因此可监听文件描述符数量不受限

​ · poll返回后,可以通过pollfd中的内容进行处理就绪文件描述符,相比select效率要高;

3.epoll函数

3.1 函数简介

​ epoll_create函数介绍:

int epoll_create(int size);    // 新建用于监听fd的根结点,其结构是一棵 红黑树
// 返回:建立的红黑树的根结点的文件描述符——epfd

epoll_create函数用于新建用于管理的监听fd。

参数说明:

​ size:目前linux版本已经忽略了size大小设置

epoll_ctl函数介绍:

int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
/*
struct epoll_event{
	uint32_t events;     // epoll事件   EPOLLIN/EPOLLOUT  EPOLLET/EPOLLLT
	epoll_data_t data;   // 用户数据
};
typedef union epoll_data{
	void     *ptr;
	int      fd;
	uint32_t u32;
	uint64_t u64;
}epoll_data_t;
*/

epoll_ctl函数用于修改、删除、添加对应文件描述符的感兴趣事件。

参数说明:

epfd:用于管理epoll_event事件的红黑树的根结点,epoll_create的返回值。

op:需要修改的操作,由宏定义给出

宏定义EPOLL_CTL_ADDEPOLL_CTL_DELEPOLL_CTL_MOD
说明添加监听事件删除监听事件修改监听事件

fd:需要修改的文件描述符fd。

event:当前文件描述符感兴趣事件。

int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);

epoll_wait函数用于监听感兴趣文件描述符,并返回就绪文件描述符数量。

参数说明:

epfd:epoll_create返回值

events:需要监听的事件数组的首地址

maxevents:events数组的大小

timeout:与poll中的timeout相似

3.2 特性

​ · epoll解决了poll与select函数的弊端,不需要遍历就绪fd,可以直接通过epoll_event中的ptr设定事件处理函数;

​ · 不需要重复拷贝感兴趣的文件描述符表,而是通过建立共享内存,实现用户空间与内核空间之间的数据传递;

​ · 使用红黑树进行管理文件描述符,查找效率高;

​ · 只拷贝就绪文件描述符链表,而不是全部感兴趣文件描述符;

​ · epoll_data结构中存在union结构,用户可自定义对应fd的事件处理函数,提高事件响应速度;

​ · epoll存在两种触发机制;

3.3 epoll的实现机制

​ 1.使用epoll_create新建一颗红黑树,用于管理感兴趣文件描述符,epoll使用共享内存实现用户空间与内核空间传输数据,因此不需要将感兴趣fd拷贝到内核空间中;

​ 2.可以使用epoll_ctl注册对应fd感兴趣的事件,此时系统会将fd添加到红黑树中,并设置对应的激活回调函数

​ 3.当fd就绪,系统会调用激活回调函数,并将该fd写入到就绪fd链表中

​ 4.最后将就绪文件描述符链表拷贝回用户空间,epoll_wait返回。此时,用户便可以通过返回的就绪fd处理对应的事件。epoll在监听时,使用回调机制实现,而不需要进行轮询,因此效率较高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值