前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >这次 moon 要把网络 I/O 一网打尽

这次 moon 要把网络 I/O 一网打尽

作者头像
moon聊技术
发布于 2022-05-27 07:02:21
发布于 2022-05-27 07:02:21
3300
举报
文章被收录于专栏:moon聊技术moon聊技术
  • 前言
  • 什么是 I/O ?
  • 网络 I/O 又是什么?
  • 为什么会有网络 I/O 模型?
  • I/O 模型
    • 阻塞 I/O
    • 非阻塞 I/O
    • 异步 I/O
    • 信号驱动模型
    • I/O 多路复用
  • 结语

前言

大家好,我是 moon,上一次和大家聊了一下 socket(这次 moon 要把 socket 玩的明明白白),相信大家对 socket 有了一定的认识,对于 socket 还不熟悉的同学,可以先看看 socket 这篇文章,今天这篇文章是基于 socket,再和大家讲一讲「网络I/O」相关的知识,也刚好为后续 netty 的文章做下铺垫

什么是 I/O ?

I:其实就是 「Input」,输入 O:其实就是 「Output」,输出 所以 I/O 很好理解,就是输入和输出

生活中最简单的例子,你用微信和别人聊天,你「发送信息」给对方,就是「输入」「对方回给你信息」,你接受到了,就是「输出」

一般情况下,在软件中我们常说的 I/O 是指「网络 I/O 和磁盘 I/O」,今天我们就来聊下网络 I/O

网络 I/O 又是什么?

其实网络 I/O 就是网络中的输入与输出,我们再说详细点,正常的网络通信中,一条消息发送的过程中有一个很重要的媒介,叫做「网卡」,它的作用有两个

  • 一是将电脑的数据封装为帧,并通过网线(对无线网络来说就是电磁波)将数据发送到网络上去
  • 二是接收网络上其它设备传过来的帧,并将帧重新组合成数据,发送到所在的电脑中。

网卡能「接收所有在网络上传输的信号」,但正常情况下只接受发送到该电脑的帧和广播帧,将其余的帧丢弃。

所以网络 I/O 其实网络与服务端(电脑内存)之间的输入与输出

为什么会有网络 I/O 模型?

一般情况下,一次网络数据的传输会从客户端发送给服务端,由服务端网卡接受,转交给内存,最后由 cpu 执行相应的业务操作

只要有一点电脑知识的读者大多数都知道,cpu、显卡、内存等电脑中你数得上名字的模块,运行效率最高的就是 cpu 了,所以「为了整个网络传输的提效,就诞生出了五种网络 I/O 模型」

当然还有一点原因

不管是客户端还是服务端,在发送和接受数据的时候,都是要与 socket 缓冲区去进行交互的,那么「什么时候交互?是否需要等待响应?」基于这些「不同的业务场景」,也就「有了五种网络 I/O 模型」

其实这个结论是通用的,「任何模型的调优改造健全一般都是围绕着性能、安全、业务场景这三个方向来前进的」

I/O 模型

好了,我们说完了 I/O 模型的诞生,就来具体的研究下具体是哪五种 I/O 模型

阻塞 I/O

阻塞 I/O,顾名思义,就是在各个状态完全阻塞住整个 I/O 过程是个串行化的,在数据传输开始时,都要等到后续的每一个操作完成后才可以继续,这也是 linux 系统默认的 I/O 模型,当然,这种模型的问题就是「效率非常的低」

第二个问题就是,如果是在生产环境多线程的情况下,会有频繁线程的「上下文切换」,而这个切换又是「非常消耗资源」的。

非阻塞 I/O

非阻塞 I/O 针对于阻塞 I/O 有了一些改进

在系统调用内核后,内核如果「没有准备好」数据,则直接会「返回一个错误码」,直到数据「准备好」后,「再走后续的流程」

中间会有一个「一直定时去询问」的动作,所以它的「缺点」也就是在这里,需要「一直去处理数据没有准备好的情况」,也「无法判断该数据多久会准备好」。但是在并发的情况下相比阻塞 I/O 来说它的性能会好很多

异步 I/O

其实通过阻塞或者非阻塞 I/O,你能发现一个问题,其实「拷贝数据都是由内核完成」的,那又「何必让应用进程去触发拷贝这个操作呢」,由内核直接完成不就好了?

所以就出现了异步 I/O 模型

比如有一个读取数据的请求,应用「只需要向内核发送一个 read」,告诉内核它要读取数据后即刻返回。

之后内核收到请求并且建立一个信号连接,当数据准备就绪,内核会主动把数据从内核复制到用户空间,「等所有操作都完成之后,内核再发起一个通知告诉应用」,完成了所有操作,应用程序可以读取数据了,这就是异步 I/O 模型。

异步 IO 的好处是「将发送询问请求、发送接收数据请求两个请求合并为一次请求」就可以完成状态询问和数拷贝的所有操作,并且「无阻塞」,内核准备好数据后直接通知。

信号驱动模型

信号驱动就是进程发起一个 IO 操作,会「向内核注册一个信号处理程序」,然后立即返回

「内核将数据报准备好」后会「发送一个信号」给进程,这时候进程便可以在信号处理程序中调用 IO 处理数据报。

I/O 多路复用

I/O 多路复用解决的问题就是「单线程怎么管理多个 socket 连接」,内核负责轮询所有 socket,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

「其主要有 select、poll、epoll 三种多路复用的网络I/O模型」

select

select 的设计思路是唤醒模式,「通过一个 socket 列表维护所有的 socket」,socket 对应文件列表中的 fd,select 会默认限制最大文件句柄数为 1024,间接控制 fd[] 最大为 1024。

  • 如果列表中的 Socket 都「没有数据」,就挂起进程。
  • 如果有一个 Socket 收到数据,就唤醒进程,将该线程从等待队列中移除,加入到工作队列,然后准备执行 socket 任务。

那么有个问题来了,如果有多个 socket 任务同时唤醒怎么办,也就是说说有多个 socket 任务同时进来,那到底执行哪个 socket 任务?

所以,当进程被唤醒后,「至少有一个 socket 是有数据的」,这时候只需要「遍历一遍 socket 列表」就知道了此次需要执行哪些 socket 了。

缺点:

  • 每次 select 都需要将进程加入到监视 socket 的等待队列,每次唤醒都要将进程从 socket 待队列移除。这里涉及两次遍历操作,而且每次都要将 FDS 列表传递给内核,有一定的开销。
  • 进程被唤醒后,只能知道有 socket 接收到了数据,无法知道具体是哪一个 socket 接收到了数据,所以需要用户进程进行遍历,才能知道具体是哪个 socket 接收到了数据。
poll

poll 其实内部实现基本跟 select 一样,区别在于它们底层组织 fd[] 的数据结构不太一样,从而实现了 poll 的最大文件句柄数量限制去除了

epoll

我们前面说到 select 是需要遍历来解决查询就绪 socket 的,效率很低,epoll 就对此做了改进

  • 1.拆分:epoll 将添加等待队列和阻塞进程拆分成两个独立的操作,不用每次都去重新维护等待队列
    • 先用 epoll_ctl 维护等待队列 eventpoll,它通过红黑树存储 socket 对象,实现高效的查找,删除和添加。
    • 再调用 epoll_wait 阻塞进程,底层是一个双向链表。显而易见地,效率就能得到提升。

select 的添加等待队列和阻塞进程是合并在一起的,每次调用select()操作时都得执行一遍这两个操作,从而导致每次都要将fd[]传递到内核空间,并且遍历fd[]的每个fd的等待队列,将进程放入各个fd的等待队列中。

  • 2.直接返回有数据的 fd[]:select 进程被唤醒后,是需要遍历一遍 socket 列表,手动获取有数据的 socket,而 epoll 是在唤醒时直接把有数据的 socket 返回给进程,不需要自己去进行遍历查询。

「直接返回有数据的 socket 是怎么实现的?」

其实就是 epoll 会先注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似 callback 的回调机制,迅速激活这个文件描述符,当进程调用 epoll_wait() 时便得到通知。

epoll对文件描述符的操作有两种模式:「LT」(level trigger)和 「ET」(edge trigger)默认为 LT :

  • LT模式:当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用epoll_wait时,会再次响应应用程序并通知此事件。
  • ET模式:当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次响应应用程序并通知此事件。

结语

I/O 模型这块儿可是重中之重,作为网络通信的核心,只要你想去大厂一定会被问到,今天这篇文章应该帮你梳理清楚了各个网络 I/O 模型之间的关系以及优缺点,让你对网络 I/O 模型有了更进一步的了解,下次我们准备开始突击 netty ~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 moon聊技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
框架篇:linux网络I/O+Reactor模型
网络I/O,可以理解为网络上的数据流。通常我们会基于socket与远端建立一条TCP或者UDP通道,然后进行读写。单个socket时,使用一个线程即可高效处理;然而如果是10K个socket连接,或者更多,我们如何做到高性能处理?
潜行前行
2020/12/11
1.1K0
框架篇:linux网络I/O+Reactor模型
关于I/O与并发
由于笔者在之前发布的一文玩转NGINX中提到过I/O复用模型,在此另起一篇文章简述相关技术。
红客突击队
2022/09/30
5990
关于I/O与并发
I/O的内核原理与5种I/O模型
我们都知道unix世界里、一切皆文件、而文件是什么呢?文件就是一串二进制流而已、不管socket、还是FIFO、管道、终端、对我们来说、一切都是文件、一切都是流、在信息交换的过程中、我们都是对这些流进行数据的收发操作、简称为I/O操作(input and output)、往流中读出数据、系统调用read、写入数据、系统调用write、不过话说回来了、计算机里有这么多的流、我怎么知道要操作哪个流呢?做到这个的就是文件描述符、即通常所说的fd(file descriptor)、一个fd就是一个整数、所以对这个整数的操作、就是对这个文件(流)的操作、我们创建一个socket、通过系统调用会返回一个文件描述符、那么剩下对socket的操作就会转化为对这个描述符的操作、不能不说这又是一种分层和抽象的思想、
小柒吃地瓜
2020/04/21
2.1K0
I/O的内核原理与5种I/O模型
IO模型
一 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步:   所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不会返回。按照这个定义,其实绝大多数函数都是同步调用。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。   举例: 1. multiprocessing.Pool下的apply #发起同步调用后,就在原地等着任务结束,根本不考虑任务是在计算还是在io
用户1214487
2018/01/24
7180
IO模型
Python之IO模型
IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步、异步、阻塞、非阻塞     同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出的答案都可能不同,比如wiki,就认为asynchronous IO和non-blocking IO是一个东西。这其实是因为不同的人的知识背景不同,并且在讨论这个问题的时候上下文(context)也不相同。所以,为了更好
新人小试
2018/04/12
9880
Python之IO模型
深入学习IO多路复用select/poll/epoll实现原理
Linux 服务器处理网络请求有三种机制,select、poll、epoll,本文打算深入学习下其实现原理。
涂明光
2022/11/27
1.8K2
Java网络编程和NIO详解3:IO模型与Java网络编程模型
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
Java技术江湖
2019/11/21
7670
Linux下的I/O复用与epoll详解
I/O多路复用有很多种实现。在linux上,2.4内核前主要是select和poll,自Linux 2.6内核正式引入epoll以来,epoll已经成为了目前实现高性能网络服务器的必备技术。尽管他们的使用方法不尽相同,但是本质上却没有什么区别。本文将重点探讨将放在EPOLL的实现与使用详解。
用户7678152
2020/09/16
2.1K0
聊聊Netty那些事儿之从内核角度看IO模型
从今天开始我们来聊聊Netty的那些事儿,我们都知道Netty是一个高性能异步事件驱动的网络框架。
bin的技术小屋
2022/01/12
7792
聊聊Netty那些事儿之从内核角度看IO模型
unix网络编程——I/O多路复用之epoll
  当程序进行IO时,如果数据尚未准备好,那么IO将处于阻塞状态。当某个进程有多个打开的文件,比如socket,那么其后的所有准备好读写的文件将受到阻塞的影响而不能操作。不借助线程,单一进程无法在同一时间服务多个文件描述符。非阻挡式IO可以作为一个解决方案,但是效率并不高。首先进程需要不断发IO请求,其次,如果程序可以休眠,让出CPU将提高效率。多任务式IO是在其中任何一个文件描述符就绪时收到通知,此时IO将不会受到阻挡,其余时间处于休眠状态,将CPU资源让给别的进程。
Mister24
2018/09/19
6730
python3--IO模型,阻塞,非阻塞,多路复用,异步,selectors模块
结论:协程任务开启,并不一定会执行,它需要I/O(阻塞)才能执行,上面代码的time.sleep(1)模拟了I/O(阻塞)
py3study
2018/08/02
1.1K0
面试系列之-Redis高性能io模型
传统的IO模型了处理一个Get请求,需要监听客户端请求(bind/listen),和客户端建立连接(accept),从 socket中读取请求(recv),解析客户端发送请求(parse),根据请求类型读取键值数据(get),最后给客户端返回结果即向 socket中写回数据(send);
用户4283147
2023/08/21
3610
面试系列之-Redis高性能io模型
一文搞懂select、poll和epoll区别
select本质上是通过设置或检查存放fd标志位的数据结构进行下一步处理。 这带来缺点:
JavaEdge
2021/02/23
3.6K0
一文搞懂select、poll和epoll区别
Linux Epoll 一网打尽
epoll同样是linux上的IO多路复用的一种实现,内核在实现时使用的数据结构相比select要复杂,但原理上并不复杂,我们力求在下面的描述里抽出主干,理清思路。
扫帚的影子
2019/11/20
1.7K0
你应该知道的五种IO模型
linux操作系统包含了五种IO模型,各种上层编程语言或者网络编程框架的上层实现都是基于操作系统的这些IO实现来实现的。
春哥大魔王
2019/11/21
4750
​网络 IO 演变发展过程和模型介绍
作者:jaydenwen,腾讯 pcg 后台开发工程师 在互联网中提起网络,我们都会避免不了讨论高并发、百万连接。而此处的百万连接的实现,脱离不了网络 IO 的选择,因此本文作为一篇个人学习的笔记,特此进行记录一下整个网络 IO 的发展演变过程。以及目前广泛使用的网络模型。 1.网络 IO 的发展 在本节内容中,我们将一步一步介绍网络 IO 的演变发展过程。介绍完发展过程后,再对网络 IO 中几组容易混淆的概念进行对比、分析。 1.1 网络 IO 的各个发展阶段 通常,我们在此讨论的网络 IO 一
腾讯技术工程官方号
2021/02/25
1.6K0
关于I/O模型,和select、poll、epoll的区别
I/O模型主要包括:阻塞IO、非阻塞IO、I/O 多路复用、异步I/O和信号I/O;
呱牛笔记
2023/05/02
4140
关于I/O模型,和select、poll、epoll的区别
一种理解同步/异步,阻塞/非阻塞,Linux IO 模型,select /poll /epoll 的方法
吕力
2017/07/24
7K4
一种理解同步/异步,阻塞/非阻塞,Linux IO 模型,select /poll /epoll 的方法
使用 libevent 和 libev 提高网络应用性能——I/O模型演进变化史
http://blog.csdn.net/hguisu/article/details/38638183(牛逼100多名)
bear_fish
2018/09/20
2.1K0
使用 libevent 和 libev 提高网络应用性能——I/O模型演进变化史
彻底搞定select、poll、epoll
上一篇文章以近乎啰嗦的方式详细描述了BIO与非阻塞IO的各种细节。如果各位还没有读过这篇文章,强烈建议先阅读一下,然后再来看本篇,因为逻辑关系是层层递进的。
蝉沐风
2023/02/01
1.8K0
彻底搞定select、poll、epoll
相关推荐
框架篇:linux网络I/O+Reactor模型
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文