计算机网络
提示:会定期更新,更新完后会注明
计算机网络背景
一、网络发展
1.独立模式
2.网络互连
3.局域网
4.广域网
局域网和广域网是一个相对的概念。
二、OSI七层模型*
- OSI(Open SystemInterconnection,开放系统互连)七层网络模型称为开放式系统互联参考模型,是一个逻辑上的定义和规范;
- 把网络从逻辑上分为了7层. 每一层都有相关、相对应的物理设备,比如路由器,交换机;
- OSI 七层模型是一种框架性的设计方法,其最主要的功能使就是帮助不同类型的主机实现数据传输;
- 它的最大优点是将服务、接口和协议这三个概念明确地区分开来,概念清楚,理论也比较完整.
- 通过七个层次化的结构模型使不同的系统不同的网络之间实现可靠的通讯;但是, 它既复杂又不实用;
三、TCP/IP五层(或四层)模型
TCP/IP通讯协议采用了5层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求
TCP/IP通讯协议采用了5层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。
1.物理层
由于物理层(光纤、网线、wifi的电磁波,集线器)一般考虑较少,所以也称为TCP/IP四层模型。
2.数据链路层
负责设备之间的数据帧的传送和识别. 例如网卡设备的驱动、帧同步、冲突检测。
有以太网、令牌环网, 无线LAN等标准. 交换机(Switch)工作在数据链路层
3.网络层
负责地址管理和路由选择. 例如在IP协议中, 通过IP地址来标识一台主机, 并通过路由表的方式规划出两台主机之间的数据传输的线路(路由). 路由器(Router)工作在网络层。
4.传输层
负责两台主机之间的数据传输. 如传输控制协议 (TCP), 能够确保数据可靠的从源主机发送到目标主机.
5.应用层
负责应用程序间沟通,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等. 我们的网络编程主要就是针对应用层。
6.分层的好处
1)**各层之间是独立的**。某一层并不需要知道它下一层是如何实现的,而仅仅需要知道该层通过层间的接口所提供的服务。由于每一层只实现一种相对独立的功能,因而可以将一个难以处理的复杂问题分解为若干个较容易处理的更小问题,这样,整个问题的复杂度就下降了。
2)**灵活性好**。当任何一层发生变化时,只要层间接口关系保持不变,则在这层以上或以下各层均不受影响,此外,对某一层提供的服务还可以进行修改。当某层提供的服务不再需要时,甚至可以将这层取消。
3)**结构上可分割开**。各层都可以采用最合适的技术来实现。
4)**易于实现和维护**。这种结构使得实现和调试一个庞大而又复杂的系统变得易于处理,因为整个系统已被分解为若干个相对独立的子系统。
5)**能促进标准化工作**。因为每一层的功能及其所提供的服务都已有了精确的说明。
分层时应注意使每一层的功能非常明确,若层数太少,就会使每一层的协议太复杂。但层数太多又会在描述和综述各层功能的系统工程任务时遇到较多的困难。
四、协议简介
协议就是一种约定。
如下:
五、封装和分用
不同的协议层对数据包有不同的称谓,在传输层叫做(数据)段(segment),在网络层叫做数据报 (datagram),在链路层叫做(数据)帧(frame).
应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部(header),称为封装
(Encapsulation).
首部信息中包含了一些类似于首部有多长, 载荷(payload)有多长, 上层协议是什么等信息.
数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部, 根据首部中的 “上层协议字段” 将数据交给对应的上层协议处理。
过程如下图:
分用:
六、套接字
1.储备知识
IP:标定全公网内唯一一台主机。
port端口号:标定特定一台主机上唯一一个进程。
IP+端口号:全网内唯一的一个进程。
套接字本质就是进程间通信。
2.端口号和Pid
Pid是每个进程都有,端口号是传输层协议的内容,只有网络进程才有端口号。
一个进程可以绑定多个端口号:因为一个进程可以打开多个文件描述符,每个文件描述符有一个端口号。
端口号保证唯一性,所以一个端口号不能被多个进程绑定。
ps:如果一个进程在运行时fork一个子进程,就实现了一个端口号多个进程。不同进程不行。
3.网络字节序
网络字节序规定好用的是大端字节序:因为通信双方的机器大小端不一致,引发问题。
按上述规则看,大端的优势在于数据可以边传边计算。以1234abcd为例,假设是个整数,先发1就可以先计算,每来一次就令当前值乘以进制(10),当下次计算之前,1*10再+2,依次类推。
七、HTTP协议
1.应用层(实例)
应用层用来解决实际问题,满足日常需求的网络程序。
如果我们要传输一些"结构化的数据" ,例如, 我们需要实现一个服务器版的加法器. 我们需要客户端把要计算的两个加数发过去, 然后由服务器进行计算, 最后再把结果返回给客户端.
方案一
- 客户端发送一个形如"1+1"的字符串;
- 这个字符串中有两个操作数, 都是整形;
- 两个数字之间会有一个字符是运算符, 运算符只能是 + ;
- 数字和运算符之间没有空格
方案二
- 定义结构体来表示我们需要交互的信息;
- 发送数据时将这个结构体按照一个规则转换成字符串, 接收到数据的时候再按照相同的规则把字符串转化回结构体;
- 这个过程叫做 “序列化” 和 “反序列化”
代码如下:
// proto.h 定义通信的结构体
typedef struct Request {
int a;
int b;
} Request;
typedef struct Response {
int sum;
} Response;
// client.c 客户端核心代码
Request request;
Response response;
scanf("%d,%d", &request.a, &request.b);
write(fd, request, sizeof(Request));
read(fd, response, sizeof(Response));
// server.c 服务端核心代码
Request request;
read(client_fd, &request, sizeof(request));
Response response;
response.sum = request.a + request.b;
write(client_fd, &response, sizeof(response));
无论我们采用方案一, 还是方案二, 还是其他的方案, 只要保证, 一端发送时构造的数据, 在另一端能够正确的进行解析, 就是ok的. 这种约定, 就是 应用层协议
HTTP(超文本传输协议)是现成的,非常好用的应用层协议。
2.URL
俗称:网址
含义
具体含义如下:
转义
像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现.
urlencode:把C++编码为C%2B%2B
urldecode:把C%2B%2B解码成C++。
3.HTTP基本特征
1.无链接
TCP建立连接和http无关,http直接向对方发送http request即可
2.无状态
http本身无状态的,并不会记录任何用户信息,request<->response,记录你的基本信息的技术coolie+session。
3.简单快速
4.cookie
1.为什么
http本身无状态
举例:在用户通过网页访问电视剧视频时,看第一集前需要登陆认证,再看第二集的时候,也需要认证,这就是无状态,http本身是无状态的。
但http是给用户使用的,无状态会带来很差的用户体验,所以使用cookie技术。
2.怎么做
实际中我们登陆一次信息,很长一段时间都不需要再次登陆。
第一次登陆如下图:
此后一段时间,浏览器的请求都会自带cookie传回来的,带有set-cookie的文件,传入服务器后,该文件会自动与服务器注册时的账号密码核对检查,因此一段时间内不需要再次登陆。
3.本质
cookie的本质还是一个浏览器中的文件,不会由于关掉浏览器、电脑等消失。
4.缺点
上述的cookie,文件里保存着你的敏感信息。那么遇到黑客攻击你的电脑、网络后,就可以通过cookie里保存的信息,获取你的文件内容。
5.session
为了解决cookie安全性的问题,提出新的session技术。
sid-session文件在服务器上。
此时由于cookie里面存放的是sid,传到服务器上是通过sid进行认证,因此sid被盗了,对方最多只能拥有一定访问权限,没法修改用户信息。而且服务器一定比自己的电脑更安全,所以session比cookie相对安全。
6.HTTP VS HTTPS
1.HTTP缺点
- 通信使用明文(不加密),会被
窃听
- 不验证双方身份,可能遭遇
伪装
- 无法证明报文的完整性,有可能遭到
篡改
2.解决方法
-
加密防止窃听
-
证书验证身份
-
完整性保护
:主要是通过MD5散列值校验
和确认文件的数字签名算法
来避免中间人攻击。
3.HTTP+加密+认证+完整性保护=HTTPS
主要使用协议是:SSL(Secure Socket Layer,安全套接字层,世界上应用最广泛的网络安全技术)或TLS(Transport Layer Security,传输层安全协议)实现。
HTTPS不是新协议,只是HTTP通信接口部分用SSL或TLS代替
。
4.效率
使用SSL时,处理速度会变慢。
慢的方式:
通信慢
:网络负载会变慢2-100倍,除去和TCP连接、发送HTTP请求、响应以外。还必须进行SSL通信,因此整体通信量会增加。处理速度慢
:不断进行加解密运算,也会更多消耗服务器和客户端的硬件资源,导致负载增强。
解决方案:
一般通过SSL加速器(专用服务器)改善
,没有根本性解决方案。
7.HTTP的方法
- GET 获取资源
- POST 传输实体主体
- PUT 传输文件
- HEAD 获得报文首部
- DELETE 删除文件
- OPTIONS 询问支持的方法
- TRACE 追踪路径
- CONNECT 要求用隧道协议连接代理
- LINK 建立和资源之间的联系
- UNLINE 断开连接关系
8.HTTP状态码
最常见的状态码, 比如 200(OK), 404(Not Found), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway)
八、传输层
数据能够从发送端传输接收端
1.再谈端口号
1.标识通信
Port标识了一个主机上进行通信的不同应用程序
在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过netstat -n查看)
2.端口号范围划分
- 0 - 1023: 知名端口号, HTTP, FTP, SSH等这些广为使用的应用层协议, 他们的端口号都是固定的.
- 1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号, 就是由操作系统从这个范围分配的.
有些服务器是非常常用的, 为了使用方便, 人们约定一些常用的服务器, 都是用以下这些固定的端口号:
- ssh服务器, 使用22端口
- ftp服务器, 使用21端口
- telnet服务器, 使用23端口
- http服务器, 使用80端口
- https服务器, 使用443
查看知名端口号命令:cat /etc/services
3.进程和端口号
- 一个进程是否可以bind多个端口号?
- 一个端口号是否可以被多个进程bind?
详见套接字部分
4.补充
- netstat 查看网络状态的重要工具。
- pidof 通过进程名, 查看进程id。
2.UDP协议
UDP 是不具有可靠性的数据报协议。细微的处理它会交给上层的应用去完成。UDP主要用于对高速传输
和实时性
有较高要求的的通信或广播通信。比如打电话。
1.UDP协议端格式
由源端口号、目的端口号、UDP长度、UDP检验和组成,共8字节。
- 16位UDP长度, 表示整个数据报(UDP首部+UDP数据)的最大长度。
- 如果校验和出错, 就会直接丢弃。
2.UDP特点
UDP传输过程类似于寄信。
- 无连接:知道IP和端口号可以直接通信,不需要连接
- 不可靠:没有确认机制,传输失败的时候收不到消息。
- 面向数据报: 不能够灵活的控制读写数据的次数和数量。每次读写数据的时候,不能读半个数据。
3.UDP缓冲区
UDP的socket既能读, 也能写, 这个概念叫做 全双工
3.TCP协议
TCP全称为 “传输控制协议
(Transmission Control Protocol”).顾名思义,要对通信的细节和过程进行详细的控制。
TCP的特点在于可靠性和效率
1.TCP协议的首部格式
- 源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去;
- 4位TCP报头长度: 表示该TCP头部有多少个32位bit(有多少个4字节); 所以TCP头部最大长度是15 * 4 = 60
- 32位序号/32位确认号:见确认应答机制
- 6位标志位:
URG: 紧急指针是否有效
ACK: 确认号是否有效,解决丢包问题。
PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走
RST: 对方要求重新建立连接; 我们把携带RST标识的称为复位报文段
SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段
FIN: 通知对方, 本端要关闭了, 我们称携带FIN标识的为结束报文段 - 窗口大小:接收缓冲区剩余空间的大小(发送方的)(
流量控制
)。 - 校验和:发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含TCP首部, 也包含TCP数据部分。
- 16位紧急指针:标识哪部分数据是紧急数据(需要插队)
2.可靠性&&保证可靠性的方式
可靠性:
只要收到了对应的应答,认为之前的数据对方已经收到!
没有绝对可靠,最后一条ACK没有回复。
1.确认应答机制
32位序号
:从客户端到服务端,TCP将每个字节的数据都进行了编号. 即为序列号。
确认序号
:每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发.,值是收到的序号+1。
乱序问题
:通过序号发送,即使网络传输过程中,数据过来的顺序有所变化,也可以通过序号知道实际顺序,解决乱序问题。
丢包问题
:丢包问题有数据丢失和确认应答丢失两种。数据丢失时,服务器没收到数据,确认序号不变。如果是确认应答丢失,那客户端收不到确认序号。
高频面试题:
TCP报文为什么要有序列号和确认应答号呢?
序列号解决的按序到达的问题,确认序号保证的确认应答的问题,可以保证两端同时通信的全双工。解决了丢包
和乱序
的问题,当然这些细节像 HTTP 协议是不关心的,是内核级协议 TCP 要做的事情。
2.超时重传
- 主机A发送数据给B之后, 可能因为网络拥堵等原因, 数据无法到达主机B;
- 如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发。但是, 主机A未收到B发来的确认应答, 也可能是因为ACK丢失了,因此主机B会收到很多重复数据. 那么TCP协议需要能够识别出哪些包是重复的包, 并且把重复的丢弃掉,这时候我们可以利用前面提到的序列号, 就可以很容易做到
去重
的效果。
3.去重问题
每次主机B的确认应答都带有对应的确认序列号, 用来告知主机A, 我已经收到了哪些数据(收到的数据为确认序列号-1以下的字节数据),下一次你要从哪里开始发送,而已经接收的数据序列号会缓存在本地等待上层应用程序消费,如果已经重复了,则会丢弃。
比如, 主机A向主机B发送了1005字节的数据, 服务器返回给客户端的确认序号是1003, 那么说明服务器只收到了1-1002的数据. 1003的数据肯定没有收到,至于1004, 1005则不确定,即使收到了,也会暂时缓存, 等主机A重发1003收到后,直接向主机A确认应答,此时确认序列号应该为1006。
3.连接管理机制&&三次握手、四次挥手
1.三次握手
(1)客户端向服务器发送SYN信号,请求建立连接;
(2)服务器端接收到客户端的请求后,发送SYN+ACK信号,表示确认建立连接;
(3)客户端收到服务器端的反馈后,向服务器端发送ACK字段表示确认,同时状态变为ESTABLISHED,表示连接建立。
2.四次挥手
(1)客户端向服务器发送FIN信号,表示通知对方,本端要关闭了;
(2)服务器端收到客户端的信号后,发送ACK信号表示确认;
(3)服务器端向客户端发送FIN信号,表示通知对方,本端也要关闭了;
(4)客户端收到后,也反馈给服务器端一个ACK信号,表示确认。
3.为什么要3次握手?1、2次可以么?偶数次可以么?
(1)用3次握手客户端和服务器都验证了一次收和发,用最小的成本验证了全双工
(2)1次或者2次,容易让服务端遭到洪水攻击,大量的SYN进来建立连接,而无论是客户端还是服务器维护连接都是需要成本的,很容易server的资源耗尽就挂掉了,所以不可以。
(3)避免服务器出现建立连接的错误判断,减少服务器资源浪费
:3次握手最后的ACK是客户端发的,一经发送,客户端马上认为连接建立成功,但是ACK在网络中传输是需要时间的,那么此时服务器有可能在一段时间后收到ACK,也有可能ACK丢失,因此客户端维护这个失败的连接就浪费了资源。服务器的资源重要性>客户端
,若是4次握手或者偶数次握手,那么势必会造成服务端同样的问题,所以选取代价最小的方式:3次握手
4.为什么要4次挥手
因为客户端和服务器的连接是双向的,全双工的,要断开就要断开从客户端到服务端的通信连接,和服务端到客户端的通信连接。(两边都要断开)
5.TCP状态转换
4.效率&&保证效率的方式
1.滑动窗口
确认应答策略, 对每一个发送的数据段, 都要给一个ACK确认应答. 收到ACK后再发送下一个数据段.这样做有一个比较大的缺点, 就是性能较差. 尤其是数据往返的时间较长的时候.
像这样的一发一收效率较低,我们可以一次发送多条:
滑动窗口
:
窗口大小指的是无需等待确认应答而可以继续发送数据的最大值.。以图片为例:
- 发送前七个段的时候, 不需要等待任何ACK, 直接发送。
- 当收到4号消息ACK的时候,窗口就可以右移一格。
- 操作系统内核为了维护这个滑动窗口, 需要开辟
发送缓冲区
来记录当前还有哪些数据没有应答; 只有确认应答过的数据, 才能从缓冲区删掉; - 窗口越大, 则网络的吞吐率就越高;
如果出现丢包:
(1)数据包抵达,ACK丢失。
不要紧,后续ACK会进行确认。
(2)数据包直接丢失。
- 当某一段报文段丢失之后, 发送端会一直收到 1001 这样的ACK, 就像是在提醒发送端 “我想要的是 1001” 一样;
- 如果发送端主机连续三次收到了同样一个 “1001” 这样的应答, 就会将对应的数据 1001 - 2000 重新发送;
- 这个时候接收端收到了 1001 之后, 再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就已经收到了, 被放到了接收端操作系统
内核的接收缓冲区
中; - 这种机制被称为 “高速重发控制”(也叫 “
快重传
”) 快重传引入拥塞控制为了防止超时重发
。
2.流量控制
- 接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送,就会造成丢包, 继而引起丢包重传等等一系列连锁反应.
- 因此
TCP支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫做流量控制
- 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段, 通过ACK端通知发送端;
- 窗口大小字段越大, 说明网络的吞吐量越高;
接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端
;- 发送端接受到这个窗口之后, 就会减慢自己的发送速度;
- 如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端
接收端如何把窗口大小告诉发送端呢?
- 过了超时重发时间,发送端会发送一个窗口探测包。
- 接收端会定时发送窗口更新通知。
3.拥塞控制
拥塞控制:超时未收到确认
虽然TCP有了滑动窗口这个大杀器, 能够高效可靠的发送大量的数据. 但是如果在刚开始阶段就发送大量的数据, 仍然可能引发问题. 因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵. 在不清楚当前网络状态下, 贸然发送大量的数据,是很有可能引起雪上加霜的.
TCP引入 慢启动
机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据
如图:为了不增长的那么快, 因此不能使拥塞窗口单纯的加倍,此处引入一个叫做慢启动的阈值,当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长。
- 当TCP开始启动的时候, 慢启动阈值等于窗口最大值;
- 在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回1;
少量的丢包, 我们仅仅是触发超时重传; 大量的丢包, 我们就认为网络拥塞;
当TCP通信开始后, 网络吞吐量会逐渐上升; 随着网络发生拥堵, 吞吐量会立刻下降;
拥塞控制, 归根结底是TCP协议想尽可能快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案
.
4.延时应答
如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小。
可以再接收到数据之后,稍微等一会再应答,这样就增加了窗口大小,当窗口较大的时候,网络吞吐量大,效率就高。
- 假设接收端缓冲区为1M. 一次收到了500K的数据;
- 如果立刻应答, 返回的窗口就是500K;
- 但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;
- 在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;
- 如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M;
那么所有的包都可以延迟应答么?
肯定也不是。
数量限制: 每隔N个包就应答一次;
时间限制: 超过最大延迟时间就应答一次;
具体的数量和超时时间, 依操作系统不同也有差异; 一般N取2, 超时时间取200ms;
九、常考题
1.面向字节流
创建一个TCP的socket, 同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区
:
- 调用write时, 数据会先写入发送缓冲区中;
- 如果发送的字节数太长, 会被拆分成多个TCP的数据包发出;
- 如果发送的字节数太短, 就会先在缓冲区里等待, 等到缓冲区长度差不多了, 或者其他合适的时机发送出去;
- 接收数据的时候, 数据也是从网卡驱动程序到达内核的接收缓冲区;
- 然后应用程序可以调用read从接收缓冲区拿数据;
- 另一方面, TCP的一个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这一个连接, 既可以读数据, 也可以写数据. 这个概念叫做
全双工
由于缓冲区的存在, TCP程序的读和写不需要一一匹配
, 例如:
- 写100个字节数据时, 可以调用一次write写100个字节, 也可以调用100次write, 每次写一个字节;
- 读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以一次read 100个字节, 也可以一次read一个字节, 重复100次;
2.粘包问题
首先要明确, 粘包问题中的 “包” , 是指的应用层的数据包。
在TCP的协议头中, 没有如同UDP一样的 报文长度 这样的字段,。
站在传输层的角度, TCP是一个一个报文过来的. 按照序号排好序放在缓冲区中。但站在应用层的角度, 看到的只是一串连续的字节数据。
那么应用程序看到了这么一连串的字节数据, 就不知道从哪到哪是一个完整的应用层数据包。(无边界)
那么如何避免粘包问题呢?
明确两个包之间的边界
- 对于定长的包, 保证每次都按固定大小读取即可;
- 对于变长的包, 可以在包头的位置, 约定一个包总长度的字段。还可以在包和包之间使用明确的分隔符。
UDP是一个一个把数据交付给应用层. 就有很明确的数据边界,因此不存在粘包问题。
十、高级IO
- io == 等待+拷贝
- 读io == 等待读事件就绪+内核数据拷贝至用户空间。
- 写io == 写事件就绪+从用户空间将数据拷贝至内核。
高效io的本质是尽可能减少等待的比重。
钓鱼eg:
1.钓鱼分几步:
- 等
- 钓
2.故事
- 张三:始终看着鱼漂。(
阻塞IO
) - 李四:左手拿着鱼竿、右手看书。(
非阻塞IO
) - 王五:给鱼竿顶部挂一个铃铛,扣手机。铃铛没响之前,也知道响了做什么(信号)。(
信号驱动IO
) - 赵六:土豪,拿了一堆鱼竿,在岸上来回看。(
多路复用、多路转接
) - 田七:派手下小王去钓鱼(任意方式),田七走了,钓满一桶鱼给老板田七打电话。(
异步IO
) - 前4个人的方式叫
同步IO
,田七的方式叫异步IO
。
任何 IO 过程中,都包含两个步骤。第一是等待,第二是拷贝
。 在实际的应用场景中,等待消耗的时间往往都远高于拷贝的时间,让 IO 更高效,最有效的办法就是让等待的时间减少,这就是 IO 多路转接的核心思想所在。
# 总结