【计算机基础】Socket IO
一、I/O 模型
一个输入操作通常包括两个阶段:
- 等待数据准备好
- 从内核向进程复制数据
对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所等待数据到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用进程缓冲区。
Unix 有五种 I/O 模型:
- 阻塞式 I/O
- 非阻塞式 I/O
- I/O 复用(select 和 poll)
- 信号驱动式 I/O(SIGIO)
- 异步 I/O(AIO)
阻塞式 I/O
应用进程被阻塞,直到数据从内核缓冲区复制到应用进程缓冲区中才返回
应该注意到,在阻塞的过程中,其它应用进程还可以执行,因此阻塞不意味着整个操作系统都被阻塞。因为其它应用进程还可以执行,所以不消耗 CPU 时间,这种模型的 CPU 利用率会比较高。
下图中,recvfrom() 用于接收 Socket 传来的数据,并复制到应用进程的缓冲区 buf 中。这里把 recvfrom() 当成系统调用。
非阻塞式 I/O
应用进程执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是需要不断的执行系统调用来获知 I/O 是否完成,这种方式称为轮询(polling)。
由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率比较低。
I/O 复用
使用 select 或者 poll 等待数据,并且可以等待多个套接字中的任何一个变为可读。这一过程会被阻塞,当某一个套接字可读时返回,之后再使用 recvfrom 把数据从内核复制到进程中。
它可以让单个进程具有处理多个 I/O 事件的能力。又被称为 Event Driven I/O,即事件驱动 I/O。
如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接,那么就需要创建相同数量的线程。相比于多进程和多线程技术,I/O 复用不需要进程线程创建和切换的开销,系统开销更小。
信号驱动 I/O
应用进程使用 sigaction 系统调用,内核立即返回,应用进程可以继续执行,也就是说等待数据阶段应用进程是非阻塞的。内核在数据到达时向应用进程发送 SIGIO 信号,应用进程收到之后在信号处理程序中调用 recvfrom 将数据从内核复制到应用进程中。
相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。
异步 I/O
应用进程执行 aio_read 系统调用会立即返回,应用进程可以继续执行,不会被阻塞,内核会在所有操作完成之后向应用进程发送信号。
异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。
五大 I/O 模型比较
- 同步 I/O:将数据从内核缓冲区复制到应用进程缓冲区的阶段(第二阶段),应用进程会阻塞。
- 异步 I/O:第二阶段应用进程不会阻塞。
同步 I/O包括前4种
二、I/O 复用
select/poll/epoll 都是 I/O 多路复用的具体实现,select 出现的最早,之后是 poll,再是 epoll
select
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select 允许应用程序监视一组文件描述符,等待一个或者多个描述符成为就绪状态,从而完成 I/O 操作。
-
fd_set 使用数组实现,数组大小使用 FD_SETSIZE 定义,所以只能监听少于 FD_SETSIZE 数量的描述符。有三种类型的描述符类型:readset、writeset、exceptset,分别对应读、写、异常条件的描述符集合。
-
timeout 为超时参数,调用 select 会一直阻塞直到有描述符的事件到达或者等待的时间超过 timeout。
-
成功调用返回结果大于 0,出错返回结果为 -1,超时返回结果为 0。
fd_set fd_in, fd_out;
struct timeval tv;// Reset the sets
FD_ZERO( &fd_in );
FD_ZERO( &fd_out );// Monitor sock1 for input events
FD_SET( sock1, &fd_in );// Monitor sock2 for output events
FD_SET( sock2, &fd_out );// Find out which socket has the largest numeric value as select requires it
int largest_sock = sock1 > sock2 ? sock1 : sock2;// Wait up to 10 seconds
tv.tv_sec = 10;
tv.tv_usec = 0;// Call the select
int ret = select( largest_sock + 1, &fd_in, &fd_out, NULL, &tv );// Check if select actually succeed
if ( ret == -1 )// report error and abort
else if ( ret == 0 )// timeout; no event detected
else
{if ( FD_ISSET( sock1, &fd_in ) )// input event on sock1if ( FD_ISSET( sock2, &fd_out ) )// output event on sock2
}
poll
int poll(struct pollfd *fds, unsigned int nfds, int timeout);
poll 的功能与 select 类似,也是等待一组描述符中的一个成为就绪状态。
poll 中的描述符是 pollfd 类型的数组,pollfd 的定义如下:
struct pollfd {int fd; /* file descriptor */short events; /* requested events */short revents; /* returned events */};
// The structure for two events
struct pollfd fds[2];// Monitor sock1 for input
fds[0].fd = sock1;
fds[0].events = POLLIN;// Monitor sock2 for output
fds[1].fd = sock2;
fds[1].events = POLLOUT;// Wait 10 seconds
int ret = poll( &fds, 2, 10000 );
// Check if poll actually succeed
if ( ret == -1 )// report error and abort
else if ( ret == 0 )// timeout; no event detected
else
{// If we detect the event, zero it out so we can reuse the structureif ( fds[0].revents & POLLIN )fds[0].revents = 0;// input event on sock1if ( fds[1].revents & POLLOUT )fds[1].revents = 0;// output event on sock2
}
比较
1. 功能
select 和 poll 的功能基本相同,不过在一些实现细节上有所不同。
- select 会修改描述符,而 poll 不会;
- select 的描述符类型使用数组实现,FD_SETSIZE 大小默认为 1024,因此默认只能监听少于 1024 个描述符。如果要监听更多描述符的话,需要修改 FD_SETSIZE 之后重新编译;而 poll 没有描述符数量的限制;
- poll 提供了更多的事件类型,并且对描述符的重复利用上比 select 高。
- 如果一个线程对某个描述符调用了 select 或者 poll,另一个线程关闭了该描述符,会导致调用结果不确定。
2. 速度
select 和 poll 速度都比较慢,每次调用都需要将全部描述符从应用进程缓冲区复制到内核缓冲区。
3. 可移植性
几乎所有的系统都支持 select,但是只有比较新的系统支持 poll
epoll
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵红黑树上,通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用 epoll_wait() 便可以得到事件完成的描述符。
从上面的描述可以看出,epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次,并且进程不需要通过轮询来获得事件完成的描述符。
epoll 仅适用于 Linux OS。
epoll 比 select 和 poll 更加灵活而且没有描述符数量限制。
epoll 对多线程编程更有友好,一个线程调用了 epoll_wait() 另一个线程关闭了同一个描述符也不会产生像 select 和 poll 的不确定情况。
工作模式
epoll 的描述符事件有两种触发模式:LT(level trigger)和 ET(edge trigger)
-
LT 模式
当 epoll_wait() 检测到描述符事件到达时,将此事件通知进程,进程可以不立即处理该事件,下次调用 epoll_wait() 会再次通知进程。是默认的一种模式,并且同时支持 Blocking 和 No-Blocking。
-
ET 模式
和 LT 模式不同的是,通知之后进程必须立即处理事件,下次再调用 epoll_wait() 时不会再得到事件到达的通知。
很大程度上减少了 epoll 事件被重复触发的次数,因此效率要比 LT 模式高。只支持 No-Blocking,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。
应用场景
很容易产生一种错觉认为只要用 epoll 就可以了,select 和 poll 都已经过时了,其实它们都有各自的使用场景。
-
select 应用场景
select 的 timeout 参数精度为微秒,而 poll 和 epoll 为毫秒,因此 select 更加适用于实时性要求比较高的场景,比如核反应堆的控制。
select 可移植性更好,几乎被所有主流平台所支持。
-
poll 应用场景
poll 没有最大描述符数量的限制,如果平台支持并且对实时性要求不高,应该使用 poll 而不是 select。
-
epoll 应用场景
只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接。
需要同时监控小于 1000 个描述符,就没有必要使用 epoll,因为这个应用场景下并不能体现 epoll 的优势。
需要监控的描述符状态变化多,而且都是非常短暂的,也没有必要使用 epoll。因为 epoll 中的所有描述符都存储在内核中,造成每次需要对描述符的状态改变都需要通过 epoll_ctl() 进行系统调用,频繁系统调用降低效率。并且 epoll 的描述符存储在内核,不容易调试。
相关文章:

【计算机基础】Socket IO
一、I/O 模型 一个输入操作通常包括两个阶段: 等待数据准备好从内核向进程复制数据 对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所等待数据到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复…...

mingw编译opencv
我这里是msys2 这个是msys2的教程 https://blog.csdn.net/qq_39942341/article/details/105931335?ops_request_misc%257B%2522request%255Fid%2522%253A%2522167821146216800197067008%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&requ…...

数据结构(八)排序
一、排序的概念以及引用概念排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,…...
函数习题:用函数实现判断一个整数是否能被n整除
Description 输入一组整数,输入0结束(这组整数不包含0),输出其中能被n整除的所有整数之和(n为整数,不用考虑n为0的情况), n及这组整数均由键盘输入。首先输入n,再输入一…...
SAP 创建会计冲销凭证
“功能描述:根据传输过来数据创建会计冲销凭证,并返回消息和状态 *”---------------------------------------------------------------------- "“本地接口: *” IMPORTING *" VALUE(IW_ZTFKCX0010) TYPE ZTFKCX0010 *" EXP…...

Jetson(Ubuntu18.04)设备无法ping通百度能ping通局域网错误集合,(神奇的是这样的情况下Todesk等远程确没有问题)
一、.打开DNS,意思是取消注释添加114.114.114.114 ,文件如下 vim /etc/systemd/resolved.conf [Resolve] #DNS #FallbackDNS #Domains #LLMNRno #MulticastDNSno #DNSSECno #Cacheyes #DNSStubListeneryes然后重启服务sudo systemctl restart systemd-resolved.se…...
Spring的@Conditional注解
前言Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。Conditional的源码定义://此注解可以标注在类和方法上 Target({ElementType.TYPE, ElementType.METHOD}) Retention(RetentionPolicy.RUNTI…...

剑指 Offer 67 把字符串转换成整数
摘要 面试题67. 把字符串转换成整数 一、字符串解析 根据题意,有以下四种字符需要考虑: 首部空格: 删除之即可;符号位:三种情况,即 , − , 无符号";新建一个变量保存符号位࿰…...

【教学典型案例】18.开门小例子理解面向对象
目录一:背景介绍业务场景:业务分析:二:实现思路1、面向过程:2、面向对象(抽象、封装、继承、多态)3、面向对象(抽象、封装、继承、多态、反射)三:实现过程1、…...
Linux环境ENV的概念
一、基本概念 环境变量的含义:程序(操作系统命令和应用程序)的执行都需要运行环境,这个环境是由多个环境变量组成的。 按变量的周期划为永久变量和临时性变量2种: 永久变量:通过修改配置文件,…...

AcWing数据结构 - 数据结构在算法比赛中的应用(下)
目录 Trie树 Trie字符串统计 最大异或对 并查集 合并集合 连通块中点的数量 食物链 堆 堆排序 模拟堆 哈希表 模拟散列表 字符串哈希 Trie树 Trie字符串统计 思路: 设 idx索引用于构建树, 结点son[节点位置][节点分支指针],cnt[]记录单…...

基于嵌入式libxml2的ARM64平台的移植(aarch64)
由于libxml在移植过程中依赖于zlib的库文件,因此本节内容包含zlib(V1.2.13)的移植libxml2(V2.10.3)的移植两部分组成。 (一)zlib的移植(基于arm64) 1、在github上下载zlib的最新源码压缩包&am…...
8. 字符串转换整数 (atoi)
题目描述 给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。 假设环境不允许存储 64 位整数(有符号或无符号)。 示例 1&#x…...

[Tomcat]解决IDEA中的Tomcat中文乱码问题
目录 1、IDEA 2、VM options 3、IDEA启动程序的存放目录 4、Tomcat 写在前面:此方法亲测有效!!! 1、IDEA 2、VM options 加上这两行: -Dfile.encodingUTF-8 -Dconsole.encodingUTF-8 3、IDEA启动程序的存放目录…...
python之dataclasses
一、场景 dataclasses模块提供了一种方便的方法来创建和管理数据对象 它可以帮助开发者更容易地创建简单的类,同时提供了一些实用的功能,例如自动实现__init__()、repr()、eq()等方法。 数据容器:如果您需要一个简单的类来存储一些数据&…...

【MapGIS精品教程】007:MapGIS投影变换案例教程
MapGIS投影变换,包括创建坐标系、定义投影、单点投影、类投影、批量投影。 文章目录 一、创建坐标系1. 创建高斯平面坐标系2. 创建阿尔伯斯投影二、定义投影三、投影变换1. 单点投影2. 类投影3. 批量投影一、创建坐标系 在MagGIS数据库中,有个空间参考系的文件夹,内置了常见…...
list数据根据属性字段去重
/*** 根据照片名称去重*/fun duplicateRemoval(list: MutableList<MediaBean>): MutableList<MediaBean>? {val mediaBeanList: MutableSet<MediaBean> if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {TreeSet(Comparator.comparing(MediaBean::f…...
java教程(2023-3-8)
第一章:HelloWorld 1.java语言介绍 public class MainTest {public static void main(String[] args) { //软件分为系统软件和应用软件 //人机交互方式: 图形化界面 命令行方式/*常用的DOS命令:1.切换盘符:盘符 :2.创建文件夹m…...

node 配置 vue npm配置
下载node 版本16https://nodejs.org/download/release/v16.16.0/node-v16.16.0-x64.msi复制安装地址,省空间,生报错老老实实复制就好D:\Program\nodejs新建node_cache和node_globalD:\Program\nodejs\node_cacheD:\Program\nodejs\node_global运行命令np…...

特斯拉、小鹏开路,城市NOA距好用还有几年?
作者 | Marshall 编辑 | 张祥威一项新技术,狂热的技术开发者往往会高估其发展速度,认为当下偶尔发生的安全问题,会随着数据积累和功能迭代被逐渐解决。 他们往往会说,“这个问题没有包含在我们的场景库中,但现在我们知…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...

海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...