【linux网络编程基础】Select,Poll,Epoll学习笔记

多路I/O复用:内核监听多个文件描述符的属性(读写缓冲区)变化,如果某个文件描述符的读缓冲区变化了,这个时候就是可以读了,将这个事件告知应用层

一、Select

1.函数API

select函数的API:

//监听多个文件描述符的属性变化(读、写、异常)
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 

FD_ZERO(int fd, fd_set* fds); 
FD_SET(int fd, fd_set* fds);
FD_ISSET(int fd, fd_set* fds); 
FD_CLR(int fd, fd_set* fds);

2.select的使用

1)运行机制

select()的机制中提供一种fd_set的数据结构,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一Socket或文件可读。
select以后最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。用户可以注册多个socket,然后不断地调用select读取被激活的socket,即可达到在同一个线程内同时处理多个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到这个目的。

2)使用步骤

  1. 使用FDZERO初始化一个fd_set对象。
  2. 调用FD_SET,把套接字加入到fd_set集合中。
  3. 调用select函数,等待返回。
  4. 完成后返回所有的fd_set集合中设置的套接字句柄的总数,对每个集合进行了相应的更新。
  5. 根据select函数的返回值,联合FD_ISSET对fd_set进行检查。
  6. 知道了集合中待解决的IO操作后,对IO进行处理。 返回1,继续进行select的调用处理。

3.优缺点

  • 优点:跨平台
  • 缺点:
    • 文件描述符1024的限制,由于FD_SETSIZE的限制
    • 只返回文件描述符的个数,具体的哪个变化需要遍历
    • 每次都需将需要监听的文件描述符集合由应用层拷贝到内核
    • 大量并发,少了活跃,select效率低

二、Poll

1.介绍

poll的机制与select类似,与select在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理。
但是poll没有最大文件描述符数量的限制,select为每个条件构造一个描述符集,而poll则是构造一个pollfd结构体数组,每个数组元素为一个结构体指针,指定一个描述符标号及其所关心的条件。

2.函数原型

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

typedef struct pollfd {
    int fd;            // 需要被检测或选择的文件描述符
    short events;      // 对文件描述符fd上感兴趣的事件
    short revents;     // 文件描述符fd上当前实际发生的事件
} pollfd_t;

三、Epoll

Epoll 在 Select 和 Poll 的基础上引入了 eventpoll 作为中间层,使用了先进的数据结构,是一种高效的多路复用技术。

1.特点

  • 没有文件描述符1024的限制
  • 以后每次监听都不需再次将需要监听的文件描述符拷贝到内核
  • 返回的是已发生变化的文件描述符,不需要遍历树

2.步骤

  1. 调用 epoll_create 建立一个 epoll 对象(在 epoll 文件系统中给这个句柄分配资源)
  2. 调用 epoll_ctl 向 epoll 对象中添加连接的套接字
  3. 调用 epoll_wait 收集发生事件的连接

这样只需要在进程启动的时候建立一个 epoll 对象,并在需要的时候向它添加或者删除连接就可以了,因此,在实际收集的时候,epoll_wait 的效率会非常高,因为调用的时候只是传递了发生 IO 事件的连接。

3.工作模式

epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

  • 水平触发:当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait() 时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你。
  • 边缘触发:当被监控的文件描述符上有可读写事件发生时,epoll_wait() 会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你。这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符。

四、总结

在这里插入图片描述
图片来源《Linux 高性能服务器编程》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值