加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

io多路复用的讲解

发布时间:2020-12-15 20:52:42 所属栏目:安全 来源:网络整理
导读:一、什么是socket? 我们都知道unix(like)世界里,一切皆文件,而文件是什么呢?文件就是一串二进制流而已,不管socket,还是FIFO、管道、终端,对我们来说,一切都是文件,一切都是流。在信息 交换的过程中,我们都是对这些流进行数据的收发操作,简称为I/O

一、什么是socket?

我们都知道unix(like)世界里,一切皆文件,而文件是什么呢?文件就是一串二进制流而已,不管socket,还是FIFO、管道、终端,对我们来说,一切都是文件,一切都是流。在信息 交换的过程中,我们都是对这些流进行数据的收发操作,简称为I/O操作(input and output),往流中读出数据,系统调用read,写入数据,系统调用write。不过话说回来了 ,计算机里有这么多的流,我怎么知道要操作哪个流呢?对,就是文件描述符,即通常所说的fd,一个fd就是一个整数,所以,对这个整数的操作,就是对这个文件(流)的操作。我们创建一个socket,通过系统调用会返回一个文件描述符,那么剩下对socket的操作就会转化为对这个描述符的操作。不能不说这又是一种分层和抽象的思想。

?

二、阻塞?

什么是程序的阻塞呢?想象这种情形,比如你等快递,但快递一直没来,你会怎么做?有两种方式:

  • 快递没来,我可以先去睡觉,然后快递来了给我打电话叫我去取就行了。
  • 快递没来,我就不停的给快递打电话说:擦,怎么还没来,给老子快点,直到快递来。

很显然,你无法忍受第二种方式,不仅耽搁自己的时间,也会让快递很想打你。
而在计算机世界,这两种情形就对应阻塞和非阻塞忙轮询。

    • 非阻塞忙轮询:数据没来,进程就不停的去检测数据,直到数据来。
    • 阻塞:数据没来,啥都不做,直到数据来了,才进行下一步的处理。

?

先说说阻塞,因为一个线程只能处理一个套接字的I/O事件,如果想同时处理多个,可以利用非阻塞忙轮询的方式,伪代码如下:

?

[cpp]? view plain? copy
?
?
?
?
  1. while?true??
  2. {??
  3. ????for?i?in?stream[]??
  4. ????{??
  5. ????????if?i?has?data??
  6. ????????read?until?unavailable??
  7. ????}??
  8. }??


我们只要把所有流从头到尾查询一遍,就可以处理多个流了,但这样做很不好,因为如果所有的流都没有I/O事件,白白浪费CPU时间片。正如有一位科学家所说,计算机所有的问题都可以增加一个中间层来解决,同样,为了避免这里cpu的空转,我们不让这个线程亲自去检查流中是否有事件,而是引进了一个代理(一开始是select,后来是poll),这个代理很牛,它可以同时观察许多流的I/O事件,如果没有事件,代理就阻塞,线程就不会挨个挨个去轮询了,伪代码如下:

?

?

[cpp]? view plain? copy
?
?
?
?
  1. while?true??
  2. {??
  3. ????select(streams[])?//这一步死在这里,知道有一个流有I/O事件时,才往下执行??
  4. ????for?i?in?streams[]??
  5. ????{??
  6. ????????if?i?has?data??
  7. ????????read?until?unavailable??
  8. ????}??
  9. }??

?

?

但是依然有个问题,我们从select那里仅仅知道了,有I/O事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。所以select具有O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长。

epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。所以我们说epoll实际上是事件驱动(每个事件关联上fd)的,此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1))伪代码如下:

[cpp]? view plain? copy
?
?
?
?
  1. while?true??
  2. {??
  3. ????active_stream[]?=?epoll_wait(epollfd)??
  4. ????for?i?in?active_stream[]??
  5. ????{??
  6. ????????read?or?write?till??
  7. ????}??
  8. }??

?

可以看到,select和epoll最大的区别就是:select只是告诉你一定数目的流有事件了,至于哪个流有事件,还得你一个一个地去轮询,而epoll会把发生的事件告诉你,通过发生的事件,就自然而然定位到哪个流了。不能不说epoll跟select相比,是质的飞跃,我觉得这也是一种牺牲空间,换取时间的思想,毕竟现在硬件越来越便宜了。

三、I/O多路复用

好了,我们讲了这么多,再来总结一下,到底什么是I/O多路复用。
先讲一下I/O模型:
首先,输入操作一般包含两个步骤:

  1. 等待数据准备好(waiting for data to be ready)。对于一个套接口上的操作,这一步骤关系到数据从网络到达,并将其复制到内核的某个缓冲区。
  2. 将数据从内核缓冲区复制到进程缓冲区(copying the data from the kernel to the process)。

其次了解一下常用的3种I/O模型:

?

?

?

?

?

?

io多路复用,是由对文件流的处理问题上而产生的,为了提高对流处理的能力。

1.阻塞模式: 刚开始文件流处理的方式很粗暴,就是等待文件流处理,有可以读写的文件就执行,效率低。

2,非阻塞忙轮询,就是无差别的扫描所有文件流,类似死循环查找文件流状态

3.优化非阻塞模式,

4.I/O复用模型,就是用到了select 和poll函数,select和poll函数可以同时阻塞多个IO操作。

5信号驱动I/O模型(signal driven io,sigio)

6.异步IO模型

?

文章转自:https://blog.csdn.net/SkydivingWang/article/details/74917897

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读