网络系列x-Linux网络IO模型

NIO TODO 归档到Linux下

结合Linux 了解socket原理 什么多路复用 selector epoll poll

时间: 1个星期(不知道什么时候创建的这些文件,反正感觉很久了,今天2019-11-14先初探一把),学习参照

https://www.jianshu.com/p/486b0965c296

https://www.jianshu.com/p/aed6067eeac9

https://juejin.im/post/5c725dbe51882575e37ef9ed

https://woshijpf.github.io/linux/2017/07/10/Linux-IO%E6%A8%A1%E5%9E%8B.html

https://tech.youzan.com/yi-bu-wang-luo-mo-xing/

背景知识一

同步与异步

所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。

所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列

如果异步调用,调用方获取异步任务结果方式

  1. 设置共享数据,执行方执行完毕后将结果设置到该共享数据中,调用方不断轮询查询该共享数据

  2. 执行方执行完毕后通知调用方

  3. 执行方执行完毕后通过回调函数将结果告知调用方(这不也是一种通知方式吗?)

阻塞与非阻塞

阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关。也就是说阻塞与非阻塞主要是程序(线程)等待消息通知时的状态角度来说的。

阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务。函数只有在得到结果之后才会返回。

非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。虽然表面上看非阻塞的方式可以明显的提高CPU的利用率,但是也带了另外一种后果就是系统的线程切换增加增加的CPU执行时间能不能补偿系统的切换成本需要好好评估

同步/异步讨论的是调用方获取任务执行结果的方式

阻塞/非阻塞讨论的是调用方在等待任务结果时是否还能干其他事

按照上面两种维度来组合,就会有 同步阻塞异步阻塞同步非阻塞异步非阻塞四种实现方案

背景知识二

用户空间与内核空间

在32位操作系统中,寻址空间(虚拟地址)是2^32(4G),为了保证内核安全,禁止用户进程直接操作内核,操作系统将虚拟地址空间划分为两部分,将0xC0000000到0xFFFFFFFF(1G)划给内核使用,称为内核空间(也就是内核态?),剩余的0x00000000到0xBFFFFFFF(3G)划分给用户进程使用,称为用户空间(也就是用户态?)

那64位操作系统岂不是可以管理2^64(17179869184G)?理论上是这样的,但实际中目前只用到了48位(262144G)

https://www.zhihu.com/question/28638698

进程阻塞

正在执行的进程,由于期待的某些事件未发生,如请求系统资源失败、等待某种操作的完成、新数据尚未到达或无新工作做等,则由系统自动执行阻塞原语(Block),使自己由运行状态变为阻塞状态。可见,进程的阻塞是进程自身的一种主动行为,也因此只有处于运行态的进程(获得CPU),才可能将其转为阻塞状态。当进程进入阻塞状态,是不占用CPU资源的

Linux IO模型

网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作

像Java世界中切皆对象一样,Linux中一切皆文件。socket也是一个文件又是怎么体现的?

https://blog.csdn.net/kingshown_WZ/article/details/52103327

https://blog.csdn.net/YEYUANGEN/article/details/6799575

对于tcp传输,需要源IP/端口,目标IP/端口四元组,每创建一个连接(socket?),客户端端内核会随机分配一个端口,但是服务端只有一个端口,那对于多个连接,服务端是怎么确定该数据包属于一个进程中的哪个连接呢?

对于一次IO访问(比如read),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以,当一个read操作发生时,它会经历两个阶段:

  1. 第一阶段:等待数据准备
  2. 第二阶段:将数据从内核复制到进程中

对于socket流而言,

  1. 第一步:等待网络上的数据分组到达,然后被复制到内核的某个缓冲区
  2. 第二步:将数据从内核缓冲区复制到应用进程缓冲区

网络IO模型有以下5中

  • 同步阻塞IO Blocking IO
  • 同步非阻塞IO Non-Blocking IO
  • 多路复用IO Multiplexing IO
  • 信号驱动IO Signal Driven IO(实际中不常用)
  • 异步IO Asynchronous IO
一、Blocking IO

在这个模型中,用户进程执行一个系统调用(recv/recvfrom),这会导致进程阻塞(不占用CPU时间片),直到数据准备好,并将数据复制到进程缓冲区,recv/recvfrom函数返回结果,最后进程再处理数据。这种模型从数据处理角度来讲是最及时的,因为数据被复制到进程缓冲区后,进程能及时处理。处理流程图如下:

image

应用进程在两个阶段都被阻塞了

关于recv和recvfrom的区别,见https://www.cnblogs.com/p2liu/archive/2013/04/17/6048755.html

二、Non-Blocking IO

以非阻塞模式打开,每隔一段时间调用recv/recvfrom,如果数据未准备好,会立即返回一个错误码。这个过程称为轮询。应用进程调用recv/recvfrom时是会被阻塞的,但是在两次调用之间是进程是未被阻塞的,可以获取CPU时间片。从内核角度来看,当收到recv/recvfrom调用时,如果数据未准备好,则立即返回错误码,如果数据已经准备好了,则将数据复制到进程缓冲区。

image

跟同步阻塞模型相比,同步非阻塞模型

优点:在轮询期间可以执行其他任务

缺点:因为是固定时间间隔轮询的(并且这个间隔不会太短),所以数据可能会在两次查询间隔时就已经准备好了,会导致响应时间加大,吞吐量下降。

三、Multiplexing IO

在讨论前面两种IO模型时,都是基于单个socket来讨论的,实际上一个系统同时会有多个socket(属于同一个用户进程或多个用户进程)。每个socket都需要轮询或被阻塞,如果有单独一个人(这里我不知道用进程、线程还是什么其他东西来描述更准确,等后续再来完善吧),如果数据准备好了,告诉用户进程,在这之前用户进程可以安心干其他事就好了。Linux下的select,poll,epoll就是来干”查看“的工作的,如果查询得知数据已经准备好了,就通知用户进程,用户进程再调用recv/recvfrom来获取数据

select ,poll,epoll三者功能是一样的,但是epoll是select和poll的改进版,具体区别见https://www.cnblogs.com/anker/p/3265058.html

我的理解,所谓的多路复用,就是将”查询数据状态“和”复制数据“两个操作分开来,并”查询操作“实现了批量化,可以一次查询多个socket的数据状态,将已经准备好的socket相关信息返回回来,用户进程再单独调用recv/recvfrom。跟同步非阻塞模型相比,节省了查询所做的工作量。

select 操作还是由用户进程调用,并且调用过程中也会被阻塞,一旦有一个socket的数据准备好了就会返回。来个不准确的总结,多路复用将部分工作批量化了,单个的操作跟同步非阻塞模型来说类似。

因此,对于单个socket来说,多路复用并没有什么优势,其优势体现在同时处理多个socket场景下,能实现高并发,什么C10K场景,比如Nginx,Redis?

image

从整个IO流程来看,前面三种模型都是用户进程主动等待并且向内核查询数据状态,因此三者都归为同步模型*

四、Asynchronous IO

相对于同步IO,异步IO不是顺序执行。用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知IO两个阶段,进程都是非阻塞的

image

使用场景

五、Signal Driven IO

暂时不了解了

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容

  • 转自: http://www.jianshu.com/p/486b0965c296 http://www.jia...
    demop阅读 3,884评论 1 21
  • 一. 操作系统概念 操作系统位于底层硬件与应用软件之间的一层.工作方式: 向下管理硬件,向上提供接口.操作系统进行...
    月亮是我踢弯得阅读 5,965评论 3 28
  • 必备的理论基础 1.操作系统作用: 隐藏丑陋复杂的硬件接口,提供良好的抽象接口。 管理调度进程,并将多个进程对硬件...
    drfung阅读 3,537评论 0 5
  • 注:1)本人非科班出身,文章的来源主要是基于一些能找到的资料,在理解的基础上做一些总结归纳,以期对IO相关的知识体...
    Drew_Zhong阅读 1,012评论 0 2
  • python之路——IO模型 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步、异步、阻塞、非阻塞 ...
    go以恒阅读 543评论 0 2