IO多路复用实现并发服务器
一.select函数
select 的调用注意事项
在使用 select 函数时,需要注意以下几个关键点:
1. 参数的修改与拷贝
readfds 等参数是结果参数 :
select 函数会直接修改传入的 fd_set(如 readfds、writefds 和 exceptfds)。
为了保留原始监听集合,通常会定义一个备份集合(如 allread_fdset),并将它的拷贝传递给 select。
示例:
fd_set allread_fdset, readfds;
FD_ZERO(&allread_fdset);
FD_SET(fd1, &allread_fdset);
FD_SET(fd2, &allread_fdset);
readfds = allread_fdset; // 拷贝到临时集合
select(..., &readfds, ...);
2. 计算 nfds
nfds 是最大文件描述符值 + 1 :
在新增监听句柄时,更新 nfds 较为简单。
在减少监听句柄时,更新 nfds 较为复杂:
如果需要精确计算,可以通过遍历或维护一个最大堆等数据结构来找到第二大的文件描述符。
或者,可以选择忽略 nfds 的更新,但可能导致性能下降。
3. 超时参数 timeout
timeout 的含义 :
如果为 NULL,表示阻塞等待,直到有事件发生。
如果指向的时间为 0,表示非阻塞模式。
如果指定超时时间,则 select 会在超时后返回。
注意:Linux 实现中,select 返回时会修改 timeout 为剩余时间 :
如果需要重复使用 timeout,需要重新初始化。
4. 返回值的处理
返回值的意义 :
-1:表示错误。
0:表示超时时间到,没有事件发生。
正数:表示监听到的事件总数(包括可读、可写和异常事件)。
优化事件处理 :
可以利用返回值避免不必要的检查。例如,如果返回值为 1,并且已经在可读集合中处理了一个事件,则无需再检查可写和异常集合。
select 的缺点
尽管 select 是一种经典的 I/O 多路复用机制,但它存在以下显著缺点:
1. 文件描述符数量限制
FD_SETSIZE 的限制 :
每个 fd_set 最多只能监听 FD_SETSIZE 个文件描述符(在 Linux 上通常是 1024)。
这一限制使得 select 不适合高并发场景。
2. 遍历效率低
需要逐一检查文件描述符 :
返回的 fd_set 是一个位图,应用程序需要对所有监听的文件描述符逐一调用 FD_ISSET 来判断是否就绪。
示例:
for (int i = 0; i < nfds; i++) {
if (FD_ISSET(i, &readfds)) {
// 处理可读事件
}
}
3. nfds 的效率问题
select 的实现方式 :
select 内部会遍历从 0 到 nfds-1 的所有文件描述符,判断每个描述符是否是关心的,并检查是否有事件发生。
即使只监听少数几个文件描述符(如 0 和 1000),select 仍然需要遍历 1001 个描述符,导致效率低下。
总结
优点
简单易用,跨平台支持广泛。
缺点
文件描述符数量受限 :最多只能监听 FD_SETSIZE 个文件描述符。
遍历效率低 :需要逐一检查文件描述符,增加了开销。
nfds 的问题 :即使监听的文件描述符稀疏分布,select 仍需遍历所有小于 nfds 的描述符。
这些缺点促使了更高效的 I/O 多路复用机制(如 poll 和 epoll)的出现,尤其是在高并发场景下,epoll 成为了更优的选择。
【1】管道select


【2】tcp服务器select


二.poll函数
poll
针对select 做了改进
底层实现 --- 用的是数组
poll --- 链表
poll 引入了事件机制
1. 遍历?
2. poll 需要在 用户空间 和 内核空间 来回拷贝
epoll
三种多路IO操作中最高效
三.epoll函数
3. epoll
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
epoll 解决了select和poll的几个性能上的缺陷:
① 不限制监听的描述符个数(poll也是),只受进程打开描述符总数的限制;
② 监听性能不随着监听描述 符数的增加而增加,是O(1) 的,
不再是轮询描述符来探测事件,而是由描述符主动上报事件; //事件机制的
③ 使用共享内存的方式,不在用户和内核之间反复传递监听的描述 符信息;
④ 返回参数中就是触发事件的列表,不用再遍历输入事件表查询各个事件是否被触发
------------------------------------------
epoll显著提高性能的前提是:
监听大量描述符,
并且每次触发事件的描述符文件非常少。
epoll的另外区别是:
①epoll创建了描述符,记得close;
②支持水平触发和边沿触发。
epoll使用注意事项:
//epoll_create
① int epoll_create(int size); //创建epoll文件描述符
参数size并不是限制了epoll所能监听的描述符最大个数,
只是对内核初始分配内部数据结构的一个建议。
返回是epoll描述符。-1表示创建失败。
//epoll_ctl
② int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); //epoll文件描述符的控制接口
功能:
epoll_ctl控制对指定描述符fd执行op操作,event是与fd关联的监听事件。
参数:
@epfd --- epoll对象
@op
op操作有三种:
添加EPOLL_CTL_ADD,
删除EPOLL_CTL_DEL,
修改EPOLL_CTL_MOD。
分别添加、删除和修改对fd的监听事件。
重复添加fd会怎样(event相同或不相同):
添加失败(errno:17, File exists)
删除和修改不存在的fd会怎样:
删除或修改失败(errno:9,Bad file descriptor)
@fd -- 关心的fd
event是与监听的fd相关联的事件信息,event->events描述了要监听的事件类型,有以下类型:
//事件类型:
EPOLLIN 可读
EPOLLOUT 可写
EPOLLRDHUP 套接口对端close或shutdown写,在ET模式下比较有用
EPOLLPRI 紧急数据可读
EPOLLERR 异常条件
EPOLLHUP 挂起,EPOLLERR和EPOLLHUP始终由epoll_wait监听,不需要用户设置
EPOLLET 边沿触发模式,在描述符状态跳变时才上报监听事件。(监听默认都是LT模式)(ET+非阻塞模式)
EPOLLONESHOT 只一次有效,设置oneshot标记,描述符在触发一次事件之后自动失效(fd还被监听),
不会再上报任何事件,直到使用EPOLL_CTL_MOD重新激活,
设置新的监听事件为止(可不可以和之前的事件一样?)。
event->data是个共用体,可以存放和fd绑定的描述符信息,
比如就存放描述符本身fd,或者一个结构体信息,包括fd,ip,port等等。
在epoll_wait返回时,只会返回一个event列表,需要从列表元素中获取fd等信息。
返回值:
返回0表示控制成功,
返回-1表示失败。
③ int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
//等待epfd上的io事件,最多返回maxevents个事件
timeout = -1 的行为是block;
timeout = 0 是立即返回
④ epoll监听ET事件时,fd必须是非阻塞套接口。
比如监听可读事件,当ET上报可读后,需要一直读fd直到遇到EAGAIN错误为止,以免遗留数据在缓冲区中。
如果fd是阻塞的,则会读到阻塞了。
EAGAIN错误对于非阻塞套接口来说不是错误,只是说没有数据可读或者没有空间可写。
EWOULDBLOCK就是EAGAIN,值都是11。
selset/poll/epoll的LT模式监听的fd可以是阻塞模式的。
⑤ 多路复用监听io事件时,如果对某个套接口监听可写事件,总是会返回可写而事实上可能没有数据要写。
处理方法:
①只有在有数据要写时才把要写的套接口加入 监听列表中,数据全部写完之后从监听列表中删除它;
②在有数据写时,首先尝试直接写,当直接写没有把数据全部写入发送缓冲区时再把这个套接口加入可写事件 监听列表。
(这种方式效率较高,需要套接口是非阻塞的,前一种方式可以是阻塞的吗?)
可以是阻塞的。

四. 特点和区别

相关文章:
IO多路复用实现并发服务器
一.select函数 select 的调用注意事项 在使用 select 函数时,需要注意以下几个关键点: 1. 参数的修改与拷贝 readfds 等参数是结果参数 : select 函数会直接修改传入的 fd_set(如 readfds、writefds 和 exceptfds…...
【漫话机器学习系列】122.相关系数(Correlation Coefficient)
深入理解相关系数(Correlation Coefficient) 1. 引言 在数据分析、统计学和机器学习领域,研究变量之间的关系是至关重要的任务。我们常常想知道:当一个变量变化时,另一个变量是否也会随之变化?如果会&…...
控制系统分类
文章目录 定义与特点1. 自治系统(Autonomous System)与非自治系统(Non-Autonomous System)自治系统非自治系统 2. 线性系统(Linear System)与非线性系统(Nonlinear System)线性系统非…...
文档操作方法得合理使用
博主介绍:✌全网粉丝5W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验…...
Python asyncIO 面试题及参考答案 草
目录 如何正确定义一个协程函数?直接调用协程会引发什么问题? 使用 async def 定义的协程与普通函数执行流程有何本质区别? 解释 asyncio.run () 的作用及与手动管理事件循环的差异 为什么协程中必须使用 await 而非 yield 挂起操作? 写出通过 async for 实现异步迭代器…...
计算机网络——交换机
一、什么是交换机? 交换机(Switch)是局域网(LAN)中的核心设备,负责在 数据链路层(OSI第二层)高效转发数据帧。它像一位“智能交通警察”,根据设备的 MAC地址 精准引导数…...
matlab和FPGA联合仿真时读写.txt文件数据的方法
在FPGA开发过程中,往往需要将MATLAB生成的数据作为原始激励灌入FPGA进行仿真。为了验证FPGA计算是否正确,又需要将FPGA计算结果导入MATLAB绘图与MATLAB计算结果对比。 下面是MATLAB“写.txt”、“读.txt”,Verilog“读.txt”、“写.txt”的代…...
解锁DeepSpeek-R1大模型微调:从训练到部署,打造定制化AI会话系统
目录 1. 前言 2.大模型微调概念简述 2.1. 按学习范式分类 2.2. 按参数更新范围分类 2.3. 大模型微调框架简介 3. DeepSpeek R1大模型微调实战 3.1.LLaMA-Factory基础环境安装 3.1大模型下载 3.2. 大模型训练 3.3. 大模型部署 3.4. 微调大模型融合基于SpirngBootVue2…...
【分布式】聊聊分布式id实现方案和生产经验
对于分布式Id来说,在面试过程中也是高频面试题,所以主要针对分布式id实现方案进行详细分析下。 应用场景 对于无论是单机还是分布式系统来说,对于很多场景需要全局唯一ID, 数据库id唯一性日志traceId 可以方便找到日志链&#…...
uniapp或者vue 使用serialport
参考https://blog.csdn.net/ykee126/article/details/90440499 版本是第一位:否则容易编译失败 node 版本 18.14.0 npm 版本 9.3.1 electron 版本 30.0.8 electron-rebuild 版本 3.2.9 serialport 版本 10.0.0 需要python环境 main.js // Modules to control app…...
机器学习12-视觉识别任务
机器学习12-视觉识别任务 分类语义分割滑动窗口滑动窗口的实现思路优点缺点现代替代方法 全卷积(Fully Convolutional Networks, FCN)FCN 的工作原理FCN 的性能优势FCN 的应用案例FCN 的局限性改进方向下采样可学习的上采样:转置卷积 目标检测区域建议Se…...
使用paramiko爆破ssh登录
一.确认是否存在目标主机是否存在root用户 重跑 CVE-2018-15473用户名枚举漏洞 检测: import paramiko from paramiko.ssh_exception import AuthenticationExceptiondef check_user(username, hostname, port):ssh paramiko.SSHClient()ssh.set_missing_host_key…...
游戏引擎学习第146天
音高变化使得对齐读取变得不可能,我们可以支持循环声音了。 我们今天的目标是完成之前一段时间所做的音频代码。这个项目并不依赖任何引擎或库,而是一个教育项目,目的是展示从头到尾运行一个游戏所需要的全部代码。无论你对什么方面感兴趣&a…...
装饰器模式--RequestWrapper、请求流request无法被重复读取
目录 前言一、场景二、原因分析三、解决四、更多 前言 曾经遇见这么一段代码,能看出来是把request又重新包装了一下,核心信息都不会改变 后面了解到这叫 装饰器模式(Decorator Pattern) :也称为包装模式(Wrapper Pat…...
【算法题】小鱼的航程
问题: 分析 分析题目,可以看出,给你一个开始的星期,再给一个总共天数,在这些天内,只有周六周日休息,其他全要游泳250公里。 那分支处理好啦 当星期为6时,需要消耗2天,…...
视频录像机视频通道是指什么
视频录像机的视频通道是指摄像机在监控矩阵或硬盘录像机设备上的视频输入的物理位置。 与摄像头数量关系:在视频监控系统中,有多少个摄像头就需要多少路视频通道,通道数量决定了视频录像机可接入摄像头的数量,一般硬盘录像机有4路…...
RISC-V医疗芯片工程师复合型转型的路径与策略
从RISC-V到医疗芯片:工程师复合型转型的路径与策略 一、引言 1.1 研究背景 在科技快速发展的当下,芯片技术已然成为推动各行业进步的核心驱动力之一。其中,RISC-V 架构作为芯片领域的新兴力量,正以其独特的优势迅速崛起,对整个芯片产业的格局产生着深远影响。RISC-V 架…...
《Gradio : AI awesome-demos》
《Gradio : AI awesome-demos》 This is a list of some wonderful demos & applications built with Gradio. Heres how to contribute yours! 🖊️ Natural language processing Demo name (link to demo)input type(s)output type(s)status badgeruDALL-ET…...
DeepSeek R1-7B 医疗大模型微调实战全流程分析(全码版)
DeepSeek R1-7B 医疗大模型微调实战全流程指南 目录 环境配置与硬件优化医疗数据工程微调策略详解训练监控与评估模型部署与安全持续优化与迭代多模态扩展伦理与合规体系故障排除与调试行业应用案例进阶调优技巧版本管理与迭代法律风险规避成本控制方案文档与知识传承1. 环境配…...
javascript实现生肖查询
今年是农历乙巳年,蛇年,今天突发奇想,想知道公元0年是农历什么年,生肖是什么。没想到AI给我的答复是,没有公元0年。我瞬间呆愣,怎么可能?后来详细查询了一下,还真是没有。具体解释如…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...
API网关Kong的鉴权与限流:高并发场景下的核心实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中,API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关,Kong凭借其插件化架构…...
