linux下的各种I/O多路复用详解---select/poll/epoll
多路复用技术是一种通过共享物理信道实现多路信号传输的通信技术其核心原理是利用复用器将多路信号合成单一信号传输接收端通过分用器分离还原。该技术主要包括频分复用FDM、时分复用TDM、波分复用WDM、码分多址CDMA和空分多址SDMA等类型其中FDM通过划分频段实现ADSL数据传输TDM采用时分片机制支持T1载波传输WDM通过不同波长光信号在光纤中实现双向通信。该部分来源于百度百科select的概念和原理select是一种事件通知机制通常用于阻塞式 I/O 操作中它允许程序在多个文件描述符上进行监视一旦某个文件描述符变得可读、可写或出现异常select会通知程序进行相应的处理。select会在多个文件描述符上设置监视例如读、写、异常状态然后它会阻塞程序直到以下事件之一发生读事件某个文件描述符准备好读取数据如套接字接收到数据。写事件某个文件描述符准备好写入数据如套接字可以发送数据。异常事件文件描述符处于异常状态如套接字连接关闭。select会返回发生事件的文件描述符列表程序可以通过这些文件描述符来进一步处理数据。select原型int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);nfds最大文件描述符值加1。通常可以传入所有需要监视的文件描述符的最大值加1。readfds用于监视哪些文件描述符可以读取即数据已准备好读取。writefds用于监视哪些文件描述符可以写入。exceptfds用于监视哪些文件描述符发生了异常。timeout指定等待事件的最长时间。如果为NULL则select会阻塞直到有事件发生如果设置为0则为非阻塞模式否则设置为一个timeval结构体表示的超时时间。select的使用struct timeval timeout; timeout.tv_sec 5; // 等待最多5秒 timeout.tv_usec 0; int ready select(socket_fd 1, readfds, NULL, NULL, timeout); if (ready 0) { perror(select error); } else if (ready 0) { printf(timeout\n); } else { if (FD_ISSET(socket_fd, readfds)) { // 如果 socket_fd 可读进行读取操作 char buffer[1024]; int len read(socket_fd, buffer, sizeof(buffer)); if (len 0) { printf(Received data: %s\n, buffer); } } }select的不足文件描述符数量限制select的最大文件描述符数目是由fd_set中的位数限制的通常在 1024 或 4096 左右。超出这个数量select将无法处理。因此在高并发的应用场景下select可能不够高效。性能瓶颈当需要监视大量的文件描述符时select会不断地遍历所有文件描述符检查哪些描述符有事件发生。这可能导致性能瓶颈特别是在大规模的并发连接情况下。无法支持优先级select不支持文件描述符的优先级调度因此它处理多个文件描述符时是公平的不会根据优先级处理某些请求。poll的概念和原理poll是select的一个改进版本常用于多路复用I/O多路复用的场景它允许程序监控多个文件描述符的状态如是否可以读写。poll原型#include poll.h int poll(struct pollfd *fds, nfds_t nfds, int timeout);fds一个pollfd结构体数组表示要监视的文件描述符及其关注的事件。nfds要监视的文件描述符的数量即fds数组的大小。timeout指定poll阻塞等待的时间单位是毫秒。如果为负数则阻塞直到有事件发生如果为 0则立即返回如果为正数则等待指定的时间后返回。poll的使用#include stdio.h #include stdlib.h #include unistd.h #include string.h #include sys/socket.h #include arpa/inet.h #include poll.h #define PORT 8080 int main() { int server_fd, new_socket; struct sockaddr_in address; int addr_len sizeof(address); // 创建服务器套接字 if ((server_fd socket(AF_INET, SOCK_STREAM, 0)) 0) { perror(socket failed); exit(EXIT_FAILURE); } address.sin_family AF_INET; address.sin_addr.s_addr INADDR_ANY; address.sin_port htons(PORT); // 绑定套接字 if (bind(server_fd, (struct sockaddr *)address, sizeof(address)) 0) { perror(bind failed); exit(EXIT_FAILURE); } // 监听客户端连接 if (listen(server_fd, 3) 0) { perror(listen failed); exit(EXIT_FAILURE); } // 创建 pollfd 结构体 struct pollfd fds[1]; fds[0].fd server_fd; fds[0].events POLLIN; // 关注可读事件 printf(Server is listening on port %d...\n, PORT); while (1) { // 调用 poll等待事件 int ret poll(fds, 1, -1); // -1 表示无限阻塞 if (ret 0) { perror(poll failed); exit(EXIT_FAILURE); } // 检查是否有可读事件 if (fds[0].revents POLLIN) { new_socket accept(server_fd, (struct sockaddr *)address, (socklen_t*)addr_len); if (new_socket 0) { perror(accept failed); continue; } printf(New connection established\n); // 读取数据 char buffer[1024] {0}; int valread read(new_socket, buffer, sizeof(buffer)); if (valread 0) { printf(Received message: %s\n, buffer); } close(new_socket); } } return 0; }poll的缺点和优点优点没有文件描述符数量的限制不像select限制了文件描述符数量poll可以处理更大规模的文件描述符。灵活的事件选择通过pollfd可以灵活地指定感兴趣的事件并且能够处理多种类型的事件。缺点性能瓶颈在大量文件描述符的情况下poll仍然会遍历所有文件描述符因此它在大规模并发连接时的性能较低。没有优先级poll处理事件的方式是均等的没有优先级调度功能。epoll的概念和原理epoll是 Linux 下提供的高效的 I/O 多路复用机制特别适用于处理大量并发连接。与select和poll相比epoll提供了更高效的方式来管理大量文件描述符。epoll相关函数epoll_create创建一个 epoll 实例返回一个文件描述符。 int epoll_create(int size); size 参数已被废弃但它仍然被要求传递。通常传入一个大于零的数。 epoll_ctl用于添加、删除或修改事件。 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); epfdepoll_create 返回的 epoll 文件描述符。 op操作类型EPOLL_CTL_ADD、EPOLL_CTL_DEL、EPOLL_CTL_MOD。 fd待操作的文件描述符。 event待监控的事件结构。 epoll_wait等待事件发生并返回就绪的文件描述符。 int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); epfdepoll_create 返回的 epoll 文件描述符。 events用于存放就绪事件的数组。 maxevents数组大小。 timeout等待时间单位毫秒可以设置为 -1永久阻塞0非阻塞或正数指定超时时间。epoll的使用#include stdio.h #include stdlib.h #include unistd.h #include string.h #include sys/socket.h #include arpa/inet.h #include sys/epoll.h #define PORT 8080 #define MAX_EVENTS 10 int main() { int server_fd, client_fd, epfd, n; struct sockaddr_in address; struct epoll_event ev, events[MAX_EVENTS]; int addr_len sizeof(address); // 创建服务器套接字 if ((server_fd socket(AF_INET, SOCK_STREAM, 0)) 0) { perror(socket failed); exit(EXIT_FAILURE); } address.sin_family AF_INET; address.sin_addr.s_addr INADDR_ANY; address.sin_port htons(PORT); // 绑定套接字 if (bind(server_fd, (struct sockaddr *)address, sizeof(address)) 0) { perror(bind failed); exit(EXIT_FAILURE); } // 监听客户端连接 if (listen(server_fd, 3) 0) { perror(listen failed); exit(EXIT_FAILURE); } // 创建 epoll 实例 epfd epoll_create1(0); if (epfd -1) { perror(epoll_create failed); exit(EXIT_FAILURE); } // 将 server_fd 添加到 epoll 监控列表中 ev.events EPOLLIN; ev.data.fd server_fd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, server_fd, ev) -1) { perror(epoll_ctl failed); exit(EXIT_FAILURE); } printf(Server is listening on port %d...\n, PORT); while (1) { // 等待事件发生 n epoll_wait(epfd, events, MAX_EVENTS, -1); if (n -1) { perror(epoll_wait failed); exit(EXIT_FAILURE); } // 处理所有就绪事件 for (int i 0; i n; i) { if (events[i].data.fd server_fd) { // 新连接到达 client_fd accept(server_fd, (struct sockaddr *)address, (socklen_t*)addr_len); if (client_fd -1) { perror(accept failed); continue; } // 将 client_fd 添加到 epoll 监控列表中 ev.events EPOLLIN; ev.data.fd client_fd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, client_fd, ev) -1) { perror(epoll_ctl failed); exit(EXIT_FAILURE); } printf(New connection established\n); } else if (events[i].events EPOLLIN) { // 有数据可读 char buffer[1024] {0}; int len read(events[i].data.fd, buffer, sizeof(buffer)); if (len 0) { printf(Received: %s\n, buffer); } else { // 客户端关闭连接 printf(Closing connection\n); close(events[i].data.fd); } } } } close(server_fd); close(epfd); return 0; }epoll的优点高效性epoll使用事件驱动模式当有文件描述符就绪时才通知应用程序因此避免了poll和select中每次都要遍历所有文件描述符的性能问题。支持大规模并发在大量并发连接的情况下epoll处理效率更高尤其是当活跃的文件描述符很少时它只会通知那些就绪的文件描述符避免了不必要的检查。支持边缘触发和水平触发epoll提供了两种触发模式可以根据需要选择。总结特性selectpollepoll最大文件描述符限制通常 1024没有最大文件描述符限制没有文件描述符数量的限制效率随着文件描述符增加性能下降随着文件描述符增加性能下降高效性能不随文件描述符数量变化API设计每次调用时需要重设文件描述符使用结构体数组使用事件驱动灵活且高效操作方式阻塞或非阻塞阻塞或非阻塞阻塞、非阻塞、事件驱动适用场景文件描述符数量较少简单应用文件描述符数量适中但不高高并发场景如大规模网络服务优点简单易用较灵活解决了 select 限制极高的性能无限制的并发处理

相关新闻

一次虚拟机翻车引发的思考:不用 Mac 也能从 Apple 服务器下载 macOS

一次虚拟机翻车引发的思考:不用 Mac 也能从 Apple 服务器下载 macOS

一次虚拟机翻车引发的思考:不用 Mac 也能从 Apple 服务器下载 macOS 【免费下载链接】gibMacOS Py2/py3 script that can download macOS components direct from Apple 项目地址: https://gitcode.com/gh_mirrors/gi/gibMacOS 周五晚上十一点,我…

2026/9/30 8:32:40 阅读更多 →
atc-react与MITRE ATTCK集成指南:提升威胁狩猎效率的终极技巧

atc-react与MITRE ATTCK集成指南:提升威胁狩猎效率的终极技巧

atc-react与MITRE ATT&CK集成指南:提升威胁狩猎效率的终极技巧 【免费下载链接】atc-react A knowledge base of actionable Incident Response techniques 项目地址: https://gitcode.com/gh_mirrors/at/atc-react atc-react作为一个专注于事件响应技术…

2026/9/27 10:38:31 阅读更多 →
免费法线贴图生成工具实战:拖一张灰度图,三步做出专业级凹凸质感

免费法线贴图生成工具实战:拖一张灰度图,三步做出专业级凹凸质感

免费法线贴图生成工具实战:拖一张灰度图,三步做出专业级凹凸质感 【免费下载链接】NormalMap-Online NormalMap Generator Online 项目地址: https://gitcode.com/gh_mirrors/no/NormalMap-Online 晚上十点,你盯着游戏场景里那块光秃秃…

2026/9/26 16:09:13 阅读更多 →

最新新闻

Jev决策模型:不生成文字的Agent架构如何颠覆传统LLM决策

Jev决策模型:不生成文字的Agent架构如何颠覆传统LLM决策

1. 一个Java老兵眼中的Jev:不生成文字的决策模型到底在做什么第一次看到Jev这个模型的时候,我的反应和大多数Java开发者一样:又一个Agent框架?市面上Agent框架已经多到快赶上Java的ORM框架数量了,LangChain、AutoGPT、…

2026/9/30 10:13:16 阅读更多 →
Ubuntu 22.04英文桌面VMware开发环境配置指南

Ubuntu 22.04英文桌面VMware开发环境配置指南

1. 为什么选Ubuntu 22.04英文桌面?——从真实开发场景倒推安装逻辑 我第一次在VMware里装Ubuntu 22.04英文桌面,不是为了“尝鲜”,而是被ROS 2 Humble的CI流水线逼的。当时团队新接入一个基于Gazebo Ignition的仿真项目,CI脚本里所…

2026/9/30 10:13:16 阅读更多 →
DeepSeek本地部署与API调用实战指南:绕过官网私有化接入

DeepSeek本地部署与API调用实战指南:绕过官网私有化接入

简介:本资源是一份面向AI开发者与自然语言处理研究者的DeepSeek模型实践指南,系统梳理了非官网环境下调用DeepSeek-R1模型的三种主流路径:硅基流动与华为云平台的API接入、ChatBox客户端配置实操,以及基于LM Studio的本地部署全流…

2026/9/30 10:13:16 阅读更多 →
Android RescueParty 救援机制:触发到 recovery 清数据

Android RescueParty 救援机制:触发到 recovery 清数据

开机动画转了两三分钟,屏幕一黑,机器自己重启了;再转,再黑,再重启。反复四五轮之后,屏幕直接跳进一个蓝底或黑底的 recovery 菜单,然后提示正在清除数据。这个场景做过定制板子、安卓盒子、车机…

2026/9/30 10:13:16 阅读更多 →
三进制模型Bonsai 2让16GB显卡流畅运行27B大模型

三进制模型Bonsai 2让16GB显卡流畅运行27B大模型

先说结论:一张 16GB 的显卡确实能跑 27B 量级的大模型,但不是靠传统的 Q4_K_M 硬压,而是靠三进制模型 Bonsai 2 这种把权重逼到 -1/0/1 的做法。我这次把 Bonsai 2 27B 的 PQ2_0 和 PTQ1_0 两个 GGUF 版本都下载下来,在 RTX 4070 …

2026/9/30 10:13:16 阅读更多 →
Model-Optimizer:模型交付前的工业化优化流水线

Model-Optimizer:模型交付前的工业化优化流水线

1. “Model-Optimizer”不是工具名,而是工程阶段的统称概念很多人第一次看到“Model-Optimizer”这个词,第一反应是去GitHub搜一个叫这个名字的开源项目,或者在PyPI里pip install model-optimizer——结果什么也找不到。我当年也这么干过&…

2026/9/30 10:12:15 阅读更多 →

日新闻

Base64 图片头部特征识别:从文件头到格式判断的完整指南

Base64 图片头部特征识别:从文件头到格式判断的完整指南

1. 项目概述:为什么说看懂 base64 图片头部是基本功这几年跟 base64 打交道的机会越来越多,后端接口返回图片、前端渲染验证码、小程序里存小图、还有一些老系统导出报表,动不动就给你一段长到怀疑人生的 base64 字符串。很多人拿到字符串就直…

2026/9/30 0:00:35 阅读更多 →
Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

简介:本资源是一份面向Java初学者与课程设计学生的公交站牌广告灯箱管理系统毕业设计文档,聚焦城市公共广告资源信息化管理痛点,提供从需求分析到技术实现的完整方案。文档采用标准学术论文结构,含摘要、英文摘要、目录及五章正文…

2026/9/30 0:00:35 阅读更多 →
用 Redis Lua 构建大模型 API 多租户原子配额治理体系

用 Redis Lua 构建大模型 API 多租户原子配额治理体系

我去年年底接了一个内部 AI 平台的治理需求,背景很直接:公司把 DeepSeek、MiniMax 这类大模型 API 统一封装成内部网关,开放给几个业务团队用。结果第一个月账单出来,额度直接超了 4 倍。仔细查日志,发现原因并不复杂—…

2026/9/30 0:00:35 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/29 8:16:59 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/29 16:41:41 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/9/29 8:24:48 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/29 19:29:29 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/29 5:58:00 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/29 3:55:56 阅读更多 →