鸿扬家装网站建设,谈谈对seo的理解,一个网站是怎么建立的,手机网站静态模板#x1f504; Linux poll() 系统调用详解一、poll 是干什么的#xff1f;poll 是 Linux#xff08;及 POSIX 标准#xff09;中用于实现 I/O 多路复用#xff08;I/O Multiplexing#xff09; 的系统调用#xff0c;它的核心作用是#xff1a;让一个线程能够同时监视多… Linux poll() 系统调用详解
一、poll 是干什么的poll 是 Linux及 POSIX 标准中用于实现 I/O 多路复用I/O Multiplexing 的系统调用它的核心作用是
让一个线程能够同时监视多个文件描述符file descriptors并等待其中任意一个变为“就绪”状态可读、可写或出现异常而无需阻塞在单个 I/O 操作上。
换句话说poll 实现了“一个线程处理多个 I/O 事件”的能力是构建并发网络程序的重要工具之一。它本质上是 select 的改进版解决了 select 的一些关键限制同时为后续更高效的 epoll 奠定了基础。
二、为什么需要 poll它解决了什么问题1. select 的局限性文件描述符数量限制select 最多只能监听 1024 个 fd由 FD_SETSIZE 决定。使用位图bitmap管理 fd 集合操作繁琐需用宏FD_SET, FD_ISSET 等。每次调用必须重置集合性能开销大且易出错。需传入最大 fd 1效率低扫描范围可能很大。2. poll 的解决方案poll 在设计上直接针对 select 的缺陷进行优化✅ 优点无 fd 数量硬限制使用动态数组理论上只受系统资源限制。使用数组结构管理 fd更直观、灵活。无需重置整个集合结构只需复用 struct pollfd 数组。不依赖位图或最大 fd避免无效扫描。
✅ poll 是 select 到 epoll 之间的重要过渡机制兼具兼容性与扩展性。三、poll 的函数原型#include poll.hint poll(struct pollfd *fds, nfds_t nfds, int timeout);返回值成功返回就绪的文件描述符数量 0超时返回 0出错返回 -1并设置 errno
四、参数详解参数类型说明fdsstruct pollfd *指向 pollfd 结构体数组的指针每个元素代表一个待监听的 fd。nfdsnfds_t通常是 unsigned long数组中元素的个数即要监听的 fd 总数。timeoutint等待超时时间毫秒。决定 poll 是阻塞、非阻塞还是限时等待。
五、核心数据结构1. struct pollfd —— 文件描述符事件结构struct pollfd {int fd; // 要监听的文件描述符short events; // 用户关心的事件类型输入short revents; // 内核返回的就绪事件输出};常见事件类型events 和 revents事件说明POLLIN数据可读包括普通数据和优先级数据POLLRDNORM普通数据可读通常与 POLLIN 等价POLLRDBAND优先级数据可读带外数据 OOBPOLLOUT数据可写POLLWRNORM普通数据可写通常与 POLLOUT 等价POLLERR错误发生自动检测无需设置 eventsPOLLHUP对端挂起或关闭连接hang upPOLLNVAL文件描述符无效未打开
⚠️ 注意events由用户设置表示关心哪些事件。revents由内核填充表示实际发生的事件。即使未在 events 中设置 POLLERR 或 POLLHUP只要发生revents 中也会包含。2. timeout 参数的三种用法情况设置方式行为永久阻塞timeout -1一直等待直到有 fd 就绪非阻塞timeout 0立即返回用于轮询限时等待timeout 5000最多等待 5000 毫秒5 秒
六、poll 的工作流程典型用法#include poll.h#include unistd.h#include stdio.h#define MAX_FDS 10struct pollfd fds[MAX_FDS];int nfds 0; // 当前监听的 fd 数量// 假设已有 listen_fd 和一些 conn_fd// 1. 初始化将监听 socket 加入fds[nfds].fd listen_fd;fds[nfds].events POLLIN;nfds;// 主循环while (1) {// 2. 调用 pollint ready poll(fds, nfds, 5000); // 等待 5 秒if (ready -1) {perror(poll);break;} else if (ready 0) {printf(Timeout: no fd ready\n);continue;}// 3. 遍历所有注册的 fd检查 reventsfor (int i 0; i nfds; i) {if (fds[i].revents POLLIN) {if (fds[i].fd listen_fd) {// 新连接到达int conn_fd accept(listen_fd, NULL, NULL);// 将新连接加入 poll 数组fds[nfds].fd conn_fd;fds[nfds].events POLLIN;nfds;} else {// 已连接 socket 有数据可读char buffer[1024];int n read(fds[i].fd, buffer, sizeof(buffer));if (n 0) {write(fds[i].fd, buffer, n); // echo} else {// 客户端关闭或出错close(fds[i].fd);// 从数组中移除可前移覆盖fds[i] fds[--nfds];i--; // 重新检查当前位置}}}if (fds[i].revents POLLHUP) {printf(FD %d hung up\n, fds[i].fd);close(fds[i].fd);fds[i] fds[--nfds];i--;}if (fds[i].revents POLLERR) {fprintf(stderr, Error on FD %d\n, fds[i].fd);close(fds[i].fd);fds[i] fds[--nfds];i--;}}}关键点poll 不会修改 events但会修改 revents。每次调用后需检查 revents 判断事件类型。删除 fd 时需手动维护数组如前移覆盖。七、poll 解决的核心问题问题poll 如何解决select 的 1024 fd 限制使用数组无硬编码限制select 的位图操作繁琐使用结构体数组语义清晰select 需传最大 fdpoll 直接传数组长度无需扫描无效范围跨平台兼容性POSIX 标准支持 Linux、BSD、macOS 等
八、poll 的缺点局限性缺点说明1. 时间复杂度仍为 O(n)每次调用需遍历所有注册的 fd即使只有一个就绪2. 用户态/内核态拷贝开销每次调用都要复制整个 pollfd 数组到内核3. 无边缘触发ET模式只支持水平触发LT可能重复通知4. 需手动管理 fd 数组添加/删除 fd 需维护数组逻辑复杂5. 不支持就绪事件批量返回优化不像 epoll 有就绪链表机制
九、现代替代方案机制优势epoll() (Linux)O(1) 通知、支持 ET、高性能Linux 首选kqueue() (BSD/macOS)类似 epoll功能强大支持过滤器机制io_uring (Linux 5.1)异步 I/O 多路复用一体化下一代标准
✅ 推荐Linux 高并发使用 epoll跨平台中等并发使用 poll学习过渡poll 是理解 epoll 的良好跳板十、总结poll 的定位项目内容本质POSIX I/O 多路复用系统调用目的单线程监听多个 fd 的 I/O 事件核心函数poll() struct pollfd核心结构pollfd 数组触发模式仅支持水平触发LT适用场景中等并发、跨平台兼容、学习 I/O 复用进阶不适用场景超高并发1万连接、极致性能要求学习价值理解从 select 到 epoll 的演进路径一句话总结 poll 是 select 的现代化替代它通过数组结构摆脱了 fd 数量限制提升了灵活性和可移植性虽然性能仍不及 epoll但它是构建跨平台高并发网络程序的重要工具也是理解现代 I/O 复用机制的关键一环。进阶建议对比 poll 与 epoll 的系统调用开销实现一个基于 poll 的简单 HTTP 服务器理解 poll 在 libevent、Redis 等项目中的使用
掌握 poll你就掌握了从传统 I/O 模型迈向高性能网络编程的中间桥梁。