文章目录

  • IO的概念
    • 但是操作系统是怎么知道当前网卡当中是有数据:
      • 中断.中断向量 中断向量表
    • 底层数据到达时操作系统做了啥:
      • 硬中断 软中断
    • 软中断
    • 硬中断
    • 中断
  • 高级IO为何高效
    • 高级IO的本质
    • 五种IO模型
    • 我们使用一个例子来讲解五种IO模型
    • 高效IO 的本质
    • 同步IO vs 异步IO
    • 为什么是内核收到数据
    • 多路IO转接高效的原因
  • fcntl

IO的概念


在网络中通过网课设备向另外一段的输入设备进行输入,
IO=我们一定会因为一些条件而无法立即发送/无法立即接收(等也是IO的基本环节)+拷贝数据

高效的IO=拷贝数据(不等待),减少单位时间内等待的比重
IO 的话题

  1. 改变等待的方式
  2. 减少等的比重

但是操作系统是怎么知道当前网卡当中是有数据:


  1. 操作系统定期的轮询
  2. 当中数据来到的时候,通过驱动提醒操作系统

我们的计算机是通过中断程序来做到的,8259,中断组件来实现的,等到外来设备来的时候,就会像CPU里面直接发送消息(数据不会发送,只是通过控制信号可以直接通知CPU)
CPU通过中断向量表,通过其中的方法进行对应的操作,而当网卡有数据,就是通知CPU去将数据从网卡里面 搬运到内存里面

中断.中断向量 中断向量表

首先我们先介绍一下中断

中断:所谓的中断就是指CPU 在正常运行程序的过程中由于内部/外部的事件的触发或因为程序预先的安排,引起CPU暂时的中断当前正在运行的程序,而转而去执行内部/外部事件,或者程序预先安排的事件的服务子程序,待中断服务子程序执行完毕之后,CPU 在返回被暂时中断的地方,(CPU接收到了信号暂时离开执行其他事情,完了之后再回来执行原本要执行的事情

中断向量:中断服务程序的入口地址

中断向量表:把系统中所有的中断类型码及其对应的中断向量按照一定规律存放在一个区域内,这个区域就叫做中断向量表

底层数据到达时操作系统做了啥:


底层网卡有数据到达时候,此时硬中断通知操作系统,操作系统生成软中断对数据进行拷贝工作

硬中断 软中断

软中断

  1. 编程时出现的异常称为软中断(中断指令发出的)
  2. 软中断是通信之间用来模拟硬中断的一种信号通信方式
  3. 中断源发出中断请求或中断信号后,CPU或接收进程在适当的时机再自动进行中断处理或者完成软中断信号对应的功能
  4. 软中断软件实现的中断,也就是程序运行时其他程序对他的中断,而硬中断时硬件实现的中断,是程序运行时设备对他的中断

硬中断

  1. 硬中断是外部事件引起的,具有随机性突发性
  2. 硬中断的中断响应周期,cpu需要发出中断回合信号,软中断的中断响应周期,不需要发送中断回合信号
  3. 硬中断是可以被屏蔽的,软中断无法被屏蔽掉
  4. 硬中断是的中断信号由中断控制器提供的,软中断的中断信号是直接发送的,无需用到中断控制器

中断

通常引入中断都是外设,系统当中数据准备就绪,需要拷贝到内存里面,需要硬件层面上的中断来完成

waitpid并没有使用中断
:本身就是一个软件,父子进程有直接的关系,子进程在退出的时候,可以根据PCB 找到父进程

高级IO为何高效

谈及高级IO为何高效,来讨论一下为何read和write低效

在之前的网络套接字代码编写的时候,我们可能使用的是read和write进行操作,使用这个还是的时候,我们在写入或者读取的时候进程都是阻塞的,此时这个就称为IO,尤其是在套接字的场景当中读取数据时候,不知道会被阻塞多久,一个进程没读完就不能进行其他的操作,我们因为只等待一个文件描述符,就在那里一直等待,所以就非常的低效率
如:read,write,recv,send,recvfrom,sendto,fopen,fread cin,cout,scanf,printf

高级IO的本质

因为调用了select poll,epoll进行等待的时候就可以等待批量的文件描述符,等待的事件重叠了,一次可以处理多个事情,所以就高效了

五种IO模型

我们使用一个例子来讲解五种IO模型

现在我们将钓鱼简化,过程可以分为等和钓两个步骤
钓鱼大佬们是怎么提高效率调到更多的鱼呢?

看看下面5个人的做法,谁最有可能调到最多的鱼儿
张三:阻塞式的钓鱼
李四:一边玩手机,时不时看看鱼鳔
王五:鱼竿带一个铃铛,忙自己的事情,等到铃铛响的时候再去钓鱼
赵六:用一大堆鱼竿,在岸边进行轮询检测,只要有一个鱼咬住钩就行了
田七:派人去钓鱼,调到了鱼就给田七打电话,钓鱼的桶就相当于一个缓冲区

答案是:赵六

  • 张三的做法就是阻塞:类似我们之前调用recv,flags设置为0,直接就是阻塞式的等待,进程放入文件描述符中的等待队列,状态被设置为!R,一直到底部有数据,且高于低水位线,操作系统才将进程的状态设置为R,放入到运行队列中,等+拷贝
  • 李四的做法是非阻塞的检测轮询检测,这个对CPU的消耗比较大,改变等待方式
  • 王五的做法是信号驱动IO,当有IO 的时候就会发送SIGIO,这个做法很高效,王五只需要做自己的事情,在有信号时,才去处理,但是信号并不是当前立即就去处理,29号信号是一个普通信号,可能会发送很多次,但是王五只处理一次,所以在比较小型的同行才会使用
  • 赵六:多路转接式钓鱼,每个鱼竿有反应的概率相同的情况,增加鱼竿的数目能让赵六将等待的事件叠加起来,很高效(select poll),鱼竿==fd
  • 田七:异步IO的思想,叫别人来帮忙钓鱼,不关系这个人怎么调到鱼的,但是帮助钓鱼的人可以采用前面的那些人的方法

高效IO 的本质

低效IO:在等待过程特别长的通信过程中,让等的时间占比特别高,此时IO大部分的时间都是在等待,所以效率就会很低,
高效IO:在一次IO中让等待的时间占比小,recv读不是立马有数据就去读取的,还要等数据超过低水位线,或者对端给我发送PSH字段才会通知上层将数据从内核拷贝数据到用户

我们的做法就是让一个中介,这个中介去执行等待,服务器只对其负责,当有客户端发起连接时,先告诉中介,中介将消息告诉服务器,服务器再执行操作,所以就不需要服务器去做无意义的等待,只要让这个中介去等待就行了

如何使用信号驱动IO

操作系统收到数据的时候,会给进程发送SIGIO,默认处理动作是忽略,我们可以注册SIGIO 的处理方法,当底层好了给我们发送信号,我们再一次调用read接收就可以了,简单IO用的多,复杂IO用的少,因为它是普通信号,只会记录一个信号,信号可能会丢失

同步IO vs 异步IO

同步IO和异步IO 的本质就是在数据拷贝的过程中,异步IO不关心数据的拷贝,只提供一个缓冲区,让OS在合适的时候拷贝到缓冲区里面,即拷贝的过程都是由OS来完成的,数据就绪的通知方案是由信号所决定的
类比:
家里来了客人,母亲在做菜,此时我是负责端菜的,我可以以同步IO的方式进行端菜,但时对于客人来说,不需要帮忙,对于客人来说就是异步的

总结
:同步IO需要用户在调用recv/read将数据拷贝到缓冲区,但是异步IO需要用户提前告知缓冲区,OS会选择合适的时机进行拷贝数据

为什么是内核收到数据

因为协议栈是自底向上收的,所以操作系统先收到,硬件,驱动,操作系统,用户,这个问题虽然简单,但是很关键,通常是我们硬件设备网卡检测到有数据的时候,然后中断拷贝到系统的缓冲区里面

多路IO转接高效的原因

如select,select的时候阻塞等待了多个文件描述符就绪,只要有一个准备好了,就会调用recv将数据读取上来,recv一次只能等待一个,因为它的参数只有一个,但是select后能保证recv不会被阻塞住了,
select只负责等待的环节,后续的recv就不会被阻塞了,因为数据已经就绪了,
但是细节还有很多,比如数据就绪我能够疯狂进行读取吗,或者我能读取一部分就不读了吗,下一次它还会送来给我读取吗


阻塞vs非阻塞

  • 但进程阻塞接口直观看到进程卡住了,等待着某个事件就绪
  • 非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程

fcntl

fcntl函数主要是用来操作文件描述符的

一个文件描述符,默认都是阻塞IO,fcntl可以让文件描述符为非阻塞的
但是骑士除了fcntl的方式,还有好几种方法,如open的时候,可以设置第二个参数为O_NONBLOCK,可以让打开的文件描述符就是非阻塞的,或者调用recv等接口的时候,设置flags 为O_NONBLOCK

   #include <unistd.h>#include <fcntl.h>int fcntl(int fd, int cmd, ... /* arg */ );

传入的cmd值不同,后面追加的参数也不一样,fcntl函数有5个功能
复制一个现有的描述符(cmd=F_DUPFD).
获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).
我们此处只是用第三种功能 获取/设置文件状态标记, 就可以将一个文件描述符设置为非阻塞.

接口测试:

测试代码:默认read读取为非阻塞,每次往标准输入里面读取一个数据,默认缓冲区为空,便会卡住让我们输入数据

非阻塞等待

#include <iostream>
using namespace std;
#include <fcntl.h>
#include <unistd.h>
#include<errno.h>void SetNonBlock(int fd)
{//获取之前文件的状态int fl=fcntl(fd,F_GETFD);if(fl<0)perror("fcntl");//把文件描述符设置为非阻塞,设计标记 fcntl(fd,F_SETFL,fl|O_NONBLOCK);
}
int main()
{//观察标准输入阻塞和非阻塞状态读取数据char ch;SetNonBlock(0);//给0设置为非阻塞while (1){sleep(1);ssize_t s = read(0, &ch, 1);if (s > 0){printf("%c\n", ch); //读取成功}else if(s<0&&(errno==EAGAIN||errno==EWOULDBLOCK))//EAGIN和EWOULDBLOCK是一样的{//非阻塞读取,底层的数据没有就位 printf("数据没有就绪\n");cout<<"continue"<<endl;}else if(errno==EINTR&&s<0)//读取被信号中断了,这个地方就是失败了{continue;}else {// cout << ch << endl;cout<<s<<endl;}cout << "............." << endl;}return 0;
}//当我们不输入的时候,就会卡住等待我们进行输入
//设置为非阻塞,当缓冲区里面没有数据的时候,read直接返回失败,ssize_t 是一个有符号整数,-1代表底层数据没有就绪,
//读取数据不算错误,而是一种通知,并且会设置errno为EAGAIN,(try again)表示底层数据没有准备好,下次再来的话,EWOULDBLOCK也同样的效果
//如果错误码是EINT表示阻塞等待时候被信号给阻塞掉了

在非阻塞的情况下,我们读取数据,如果数据没有就绪,系统是以出错的形式返回的(不是错误)

没有就绪和真正的错处,使用同样的方式标识的,如何进一步区分呢?errno=11()
EAGAIN(EWOULDBLOCK):给非阻塞用的,这两个是一样的,errno=11,底层没有就绪,try again

什么叫做等事件就绪,
IO事件就绪

  1. 读事件就绪,读缓冲区里面有数据,为了减少用户态内核态的过度切换,就让一次读取的数据足够多,水位线(低于就发)
  2. 写事件就绪,发送的缓冲区有足够的空间进行拷贝

多路IO转接——前导相关推荐

  1. epoll实现多路io转接

    epoll实现多路IO转接思路: lfd = socket(); 监听连接事件lfd bind(); listen(); int epfd = epoll_create(1024); epfd, 监听 ...

  2. 多路 IO 转接 :select 函数

    (1)头文件: #include <sys/select.h> (2)函数原型: int select( int nfds, fd_set *readfds, fd_set *writef ...

  3. Linux中的多路IO转接,转载

    linux系统对于多路i/o转接提供了几个强大的函数,但是这些函数各有优缺点,参照网上的资料以及自己的测试,总结如下: 首先看一个程序的例子: #include        <time.h&g ...

  4. 多路 IO 转接 :epoll 函数

    因为 select 和 poll 的返回值特性,所以想判断到底哪个文件描述符发生了事件,需要遍历文件描述符表,因此,在"高并发.少访问"情况下,比如 1000 个连接,就 3 个发 ...

  5. 多路 IO 转接 :poll 函数

    (1)头文件 #include <poll.h> (2)函数原型 int poll (struct pollfd *fds, nfds_t nfds, int timeout); (3)参 ...

  6. 多路IO转接服务器 epoll

    创建一个epoll句柄,参数size用来告诉内核监听的文件描述符的个数,跟内存大小有关. #include <sys/epoll.h> int epoll_create(int size) ...

  7. select 实现类似多线程_linux进程通信--socket套接字(四)--多路IO转实现一个server对应多个client...

    先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题 一 why 在前 ...

  8. 29.Linux网络编程熟练掌握 TCP 状态张换图熟练堂握端口复用的方法了解半关闭的概念和实现方式了解多路10 转接模型熟练掌握 select 函数的使用熟练使用 fdset 相关函数的使用能够编写

    把昨天的 第二天的内容说一下,复习一下,第二天 讲的东西不算多,但是有两个作业题来写一写, 大致浏览一下,三次握手 四次挥手的过程,大家有没有画一下? 能画出来吗?同学们,大家注意 这个写代码的时候其 ...

  9. Linux网络编程(高级IO)-典型IO,多路IO复用

    IO:输入输出   过程:等待IO就绪,进行数据拷贝 四种典型IO方式: (1)阻塞IO:发起IO调用,若IO未就绪(IO条件不具备)则一直等待 (2)非阻塞IO:发起IO调用,若IO未就绪(IO条件 ...

最新文章

  1. Bzoj3060 [Poi2012]Tour de Byteotia
  2. 采用的php cms分校站点 打开特别慢,phpcms v9 打开网站特别慢 增加数据库缓存方法...
  3. best introduction to camera calibration
  4. 前端学习(2818):小程序学习之文件建立
  5. PHP和MySQL Web开发从新手到高手,第7天-创建author管理页面
  6. Kotlin入门(5)字符串及其格式化
  7. GitHub 疑被审查?著名“换脸”开源项目遭限制访问
  8. ubuntu16.04下ROS操作系统学习笔记(四 )机器人系组成、URDF机器人建模、xacro模型优化
  9. python中的fft带通滤波器
  10. apple pay充游戏后退款_iOS退款内幕
  11. 嵌入式驱动开发学习路线
  12. matlab 平滑曲线连接_【小微技能】:数学建模比赛中MATLAB的实用技巧
  13. 将已有的文件夹添加到git
  14. java中实现注册时Email邮件激活验证
  15. linux 安装 pcre
  16. mysql 数据库清理缓存
  17. PKU四日游(信息科学夏令营)
  18. WPF 精修篇 滑条
  19. 基础 | 并发编程 - [LongAdder Striped64]
  20. Linux虚拟机断电后开机出现:Entering emeryency mode. Exit the shell to continue.

热门文章

  1. linux上安装lftp
  2. sata3.0 linux内核,编译Linux内核3.0系统出现的警告信息
  3. Windows Server 2016 搭建 FTP
  4. 记HP 12c的一个坑
  5. 现有的几个Unity热更新方案该如何选择,各自的优缺点是什么?
  6. 天球坐标系、地球坐标系、地理坐标系、投影坐标系...一次搞清
  7. Vue整合SpringBoot项目实战之Vue+Element-Ui搭建前端项目
  8. 植树节,送 25 本书福利一下
  9. 谈NAND Flash的底层结构和解析
  10. 业内人士对20家N卡品牌的经典点评