写点什么

Android C++ 系列:Linux Socket 编程(四)多路 IO 转接服务器

作者:轻口味
  • 2021 年 12 月 16 日
  • 本文字数:1396 字

    阅读完需:约 5 分钟

1. select

  1. select 能监听的文件描述符个数受限于 FD_SETSIZE,一般为 1024,单纯改变进程打开 的文件描述符个数并不能改变 select 监听文件个数

  2. 解决 1024 以下客户端时使用 select 是很合适的,但如果链接客户端过多,select 采用 的是轮询模型,会大大降低服务器响应效率,不应在 select 上投入更多精力


#include <sys/select.h>/* According to earlier standards */ #include <sys/time.h>#include <sys/types.h>#include <unistd.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
void FD_CLR(int fd, fd_set *set);把文件描述符集合里fd清0
复制代码


  • nfds: 监控的文件描述符集里最大文件描述符加 1,因为此参数会告诉内核检测前多少个文件描述符的状态

  • readfds:监控有读数据到达文件描述符集合,传入传出参数

  • writefds:监控写数据到达文件描述符集合,传入传出参数

  • exceptfds:监控异常发生达文件描述符集合,如带外数据到达异常,传入传出参数

  • timeout:定时阻塞监控时间,3 种情况

  • NULL,永远等下去

  • 设置 timeval,等待固定时间

  • 设置 timeval 里时间均为 0,检查描述字后立即返回,轮询


struct timeval {  long tv_sec;/* seconds */  long tv_usec;/*microseconds */};int FD_ISSET(int fd, fd_set *set); void FD_SET(int fd, fd_set *set); void FD_ZERO(fd_set *set);测试文件描述符集合里fd是否置1 把文件描述符集合里fd位置1 把文件描述符集合里所有位清0
复制代码

2. poll

#include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);struct pollfd {   int fd; /* 文件描述符 */  short events; /* 监控的事件 */  short revents;/* 监控事件中满足条件返回的事件 */};
复制代码


  • POLLIN 普通或带外优先数据可读,即 POLLRDNORM | POLLRDBAND

  • POLLRDNORM-数据可读

  • POLLRDBAND-优先级带数据可读

  • POLLPRI 高优先级可读数据

  • POLLOUT 普通或带外数据可写

  • POLLWRNORM-数据可写

  • POLLWRBAND-优先级带数据可写

  • POLLERR 发生错误

  • POLLHUP 发生挂起 POLLNVAL 描述字不是一个打开的文件


nfds 监控数组中有多少文件描述符需要被监控 timeout 毫秒级等待


  • -1:阻塞等,#define INFTIM -1 Linux 中没有定义此宏

  • 0:立即返回,不阻塞进程

  • 0:等待指定毫秒数,如当前系统时间精度不够毫秒,向上取值


如果不再监控某个文件描述符时,可以把 pollfd 中,fd 设置为-1,poll 不再监控此 pollfd,下次返回时,把 revents 设置为 0。


ppoll GNU 定义了 ppoll(非 POSIX 标准),可以支持设置信号屏蔽字,可参考 poll 模型自 行实现 C/S

3. epoll

epoll 是 Linux 下多路复用 IO 接口 select/poll 的增强版本,它能显著提高程序在大量并 发连接中只有少量活跃的情况下的系统 CPU 利用率,因为它会复用文件描述符集合来传递结 果而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点 原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核 IO 事件 异步唤醒而加入 Ready 队列的描述符集合就行了。


目前 epell 是 linux 大规模并发网络程序中的热门首选模型。


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


一个进程打开大数目的 socket 描述符cat /proc/sys/fs/file-max

4. 总结

本文介绍了 Linux 多路复用的三种技术:select、poll、epoll。

发布于: 2021 年 12 月 16 日阅读数: 7
用户头像

轻口味

关注

🏆2021年InfoQ写作平台-签约作者 🏆 2017.10.17 加入

Android、音视频、AI相关领域从业者。 邮箱:qingkouwei@gmail.com

评论

发布
暂无评论
Android C++系列:Linux Socket编程(四)多路IO转接服务器