💻 Computer Basics
1、计算机网络
1.1 传输层:TCP和UDP
1.1.1 三次握手
1.1.2 四次挥手
1.1.3 流量控制
1.1.4 拥塞控制
1.1.5 TCP和UDP的区别
1.1.6 TCP如何保证传输的可靠性
1.1.7 TCP长连接和短连接
1.1.8 应用层提高UDP协议可靠性的方法
1.1.9 UDP和IP的首部结构
1.2 应用层:HTTP和HTTPS
1.2.1 HTTP和HTTPS的区别
1.2.2 GET和POST的区别
1.2.3 Session与Cookie的区别
1.2.4 从输入网址到获得页面的过程(越详细越好)
1.2.5 HTTP请求有哪些常见的状态码
1.2.6 什么是RIP,算法是什么
1.2.7 HTTP1.1和HTTP2.0的主要区别
1.2.8 DNS
1.2.9 HTTPS加密和认证过程
1.2.10 常见网络攻击
1.2.11 REST
1.3 计算机网络体系结构
1.4 网络层协议
1.4.1 IP地址的分类
1.4.2 划分子网
1.4.3 什么是ARP协议
1.4.4 NAT协议
2、操作系统
2.1 进程和线程
2.1.1 进程和线程的区别
2.1.2 进程间通信方式
2.1.3 同步原语
2.1.4 进程状态
2.1.5 进程调度策略
2.1.6 僵尸进程和孤儿进程
2.1.7 协程
2.1.8 异常控制流
2.1.9 IO多路复用
2.1.10 用户态和内核态
2.2 死锁
2.3 内存管理
2.3.1 分段与分页
2.3.2 虚拟内存
2.3.3 页面置换算法
2.3.4 局部性原理
2.3.5 缓冲区溢出
2.4 磁盘调度
-
+
tourist
register
Sign in
IO多路复用
## 1 什么是文件描述符 1. 文件描述符在形式上是一个**非负整数**。 2. 实际上,他是一个**索引值**,**指向内核为每一个进程所维护该进程打开文件的记录表**。 3. 当程序**打开一个现有文件**或者**创建一个新文件**时,**内核向该进程返回一个文件描述符**。 ## 2 水平触发和边缘触发 ### 2.1 含义 1. **水平触发**(LT, Level Trigger)模式下,**只要一个文件描述符就绪,就会触发通知**,如果**用户程序没有一次性把数据读写完,下次还会通知**。 2. **边缘触发**(ET, Edge Trigger)模式下,当**文件描述符从未就绪变为就绪时通知一次,之后不会再通知**,直到**再次从未就绪变为就绪**。 ### 2.2 区别 1. **边缘触发效率更高,减少了被重复触发的次数**,函数**不会返回大量用户程序可能不需要的文件描述符**。 ### 2.3 为什么边缘触发一定要用非阻塞 IO 1. **避免由于一个描述符的阻塞读/写操作让处理其他描述符的任务出现饥饿状态**。 ## 3 五种 IO 模型 常见的 IO 模型主要有五种,分别是**阻塞 IO**(Blocking IO, BIO)、**非阻塞 IO**(NoneBlocking IO, NIO)、**IO 多路复用**(IO Multiplexing)、**信号驱动 IO**(Signal Driven IO)、**异步 IO**(Asynchronous IO, AIO)。 ### 3.1 阻塞 IO 1. 阻塞 IO 是一种最传统的 IO 模型,在**读写数据过程中会发生阻塞现象**。 2. 当**用户线程发出 IO 请求**之后,**内核会去查看数据是否就绪**,如果**没有就绪就会等待数据就绪**,此时**用户线程**就会处于**阻塞**状态,同时用户线程会**交出 CPU**。 3. 当**数据就绪**之后,**内核会将数据拷贝到用户线程**,此时**用户线程**才会**解除阻塞状态**。 4. 比如 A 同学排队买票,他只能排队买上票才可以离开,这一过程就可以看成是使用了阻塞 IO 模型,因为在没买到票之前,他不能离开队伍做别的事情。 5. 很显然,阻塞 IO 模型是**同步**的。 ![图片](/media/202105/2021-05-20_112421.png) ### 3.2 非阻塞 IO 1. 当**用户线程发起一个 IO 请求**后,并**不需要等待**,而是**马上就得到一个结果**: 1. 如果**结果是一个 `error`** 时,他就知道**数据还没有准备好**,于是他可以**再次发送 IO 请求**。 2. 一旦**内核中的数据准备好了**,并且又**再次收到了用户线程的请求**,那么他**马上就将数据拷贝到了用户线程,然后返回**。 2. 在非阻塞 IO 模型中,**用户需要不断地询问内核数据是否就绪**,也就是说**非阻塞 IO 不会交出 CPU**,而是**一直占用 CPU**,这**会导致 CPU 占用非常高**。 3. 比如 A 同学在买票过程中,采用了取号买票,在没有到他前,他可以不断的返回购票大厅看下是不是到了自己的号,中间的过程可以做其它的事情,这样他就不用向之前一样一刻也不能离开购票大厅了。 4. 对于非阻塞模型来说,他**只有检查数据是否到达的时候是非阻塞的**,在数据到达时依然**需要等待内核复制数据到用户空间**,因此他还是**同步**的。 ![图片](/media/202105/2021-05-20_114304.png) ### 3.3 IO 多路复用 #### 3.3.1 原理 1. 所谓 IO 多路复用机制,就是说通过一种**机制**,可以**监视多个描述符**,一旦**某个描述符就绪**(一般是读就绪或写就绪),能够**通知程序进行相应的读写操作**,这种机制的使用**需要 `select`、`poll`、`epoll` 来配合**。 2. 在 IO 多路复用模型中,**会有一个内核线程不断地去轮询多个 `socket` 的状态**,只有**当真正读写事件发送**时,**才真正调用实际的 IO 读写操作**。 3. 在 IO 多路复用模型中,只需要使用**一个线程就可以管理多个 `socket`**,**系统不需要建立新的进程或者线程**,也**不必维护这些线程和进程**,并且**只有真正有读写事件进行时**,**才会使用 IO 资源**,所以他**可以大大减少资源占用**。 4. 比如 A 同学来买北京到南京的车票,发现有一排售票窗口,售票服务人员告诉他这些窗口目前没有票,等有票再告诉他,于是等啊等(`select` 调用中),过了一会,售票服务人员告诉他有票了,但不知道是哪个窗口卖北京到南京的票,需要让他自己看,于是 A 同学一个窗口一个窗口的问,直到找到卖北京到南京车票的窗口买上票(`recv`),`epoll` 也属于 IO 复用模型,主要区别在于**售票服务人员告诉 A 同学哪几个窗口卖北京到南京的车票,不需要一个个去问了**。 5. IO 多路复用本质上也是**同步**的,因为他们需要**在读写事件就绪后自己负责进行读写**,也就是说**这个读写过程是阻塞的**。 ![图片](/media/202105/2021-05-20_141102.png) #### 3.3.2 实现 ##### 3.3.2.1 select ###### 3.3.2.1.1 原理 1. 将**文件描述符放入一个集合**中,**调用 `select` 时**,**将这个集合从用户空间拷贝到内核空间**,由**内核根据就绪状态修改该集合的内容**。 2. 采用**水平触发**机制,只要**一个文件描述符就绪**,就**会触发通**知,如果用户程序**没有一次性把数据读写完**,**下次还会通知**。 3. **`select` 返回后**,需要通过**遍历这个集合**,**找到就绪的文件描述符**,当**文件描述符的数量增加**时,**效率会线性下降**。 ###### 3.3.2.1.2 缺点 1. **单个进程打开的文件描述符是有限制的**,可以通过`FD_SETSIZE` 设置,默认是 1024。 2. **每次调用 `select`**,都**需要把文件描述符集合从用户态拷贝到内核态**,当**文件描述符很多时这个开销会很大**。 3. **`select` 返回后**,**不管哪个 `socket` 是活跃的**,都要**遍历一下文件描述符的集合**,这会**浪费很多 CPU 时间**,**效率较低**。 ##### 3.3.2.2 poll ###### 3.3.2.2.1 原理 1. `poll` 和`select` 几乎没有区别,主要的区别在于**文件描述符的存储方式不同**,`poll`**采用链表的方式存储**,**没有最大存储数量的限制**。 ##### 3.3.2.3 epoll 1. 通过**内核和用户空间共享内存**,**避免了不断复制的问题**。 2. **支持的同时连接数上限很高**(1G 左右的内存支持 10W 左右的连接数)。 3. 文件描述符就绪时,采用**回调机制**,**回调函数将就绪的文件描述符添加到一个链表中**,**执行 `epoll_wait` 时**,**返回这个链表**,**避免了轮询**。 4. **支持水平触发和边缘触发**,采用**边缘触发机制**时,只有**活跃的文件描述符才会触发回调函数**。 #### 3.3.3 什么时候使用 select/poll,是么时候使用 epoll 1. 当**连接数较多**并且**有很多的不活跃连接**时,`epoll`**的效率比其它两者高很多**。 2. 但是当**连接数较少**并且**都十分活跃**的情况下,由于`epoll`**需要很多回调**,因此**性能可能低于其他两者**。 ### 3.4 信号驱动 IO 1. 在信号驱动 IO 模型中,当**用户线程发起一个 IO 请求**操作,会**给对应的 `socket` 注册一个信号函数**,然后**用户线程会继续执行**。 2. 当**内核数据就绪时**,会**发送一个信号给用户线程**,**用户线程接收到信号后**,便**在信号函数中调用 IO 读写操作来进行实际的 IO 请求操作**。 3. 这个**一般用于 UDP**中,**对 TCP 套接字几乎没用**,原因是该信号产生的过于频繁,并且该信号的出现并没有告诉我们发生了什么请求。 4. 比如 A 同学让售票服务人员等有票的时候通知他,没过多久 A 同学得知有票了,于是跑去买票。 5. 由于**读写操作还是需要信号函数来完成**,所以信号驱动 IO 也是**同步**的。 ![图片](/media/202105/2021-05-20_153624.png) ### 3.5 异步 IO 模型 1. 异步 IO 模型是**调用 `aio_read`**,让**内核数据准备好**,并且**复制到用户进程空间后执行指定好的函数**。 2. 例如 A 同学让售票服务人员帮他买好票后通知他,整个过程 A 同学都可以做别的事情。 3. 前面的四种 IO 模型实际上都属于同步 IO,只有最后一种是真正的**异步 IO**,因为无论是多路复用模型还是信号驱动模型,**IO 操作的第 2 个阶段都会引起用户线程阻塞**,也就是**内核进行数据拷贝的过程会让用户线程阻塞**。 ![图片](/media/202105/2021-05-20_155626.png) ## 4 参考文献 1. [什么是 IO 多路复用?怎么实现?](https://github.com/wolverinn/Waking-Up/blob/master/Operating%20Systems.md#%E4%BB%80%E4%B9%88%E6%98%AFIO%E5%A4%9A%E8%B7%AF%E5%A4%8D%E7%94%A8%E6%80%8E%E4%B9%88%E5%AE%9E%E7%8E%B0) 2. [I/O 多路复用底层原理前篇 - 五种 IO 模型](https://mp.weixin.qq.com/s/T-hP3wt4whtvVh1H1LBU3w)。 3. [彻底理解 IO 多路复用实现机制](https://juejin.cn/post/6882984260672847879)。 4. [5 中 IO 模型整理总结](https://www.cnblogs.com/dushangguzhousuoli/p/10822262.html)。
ricear
Aug. 3, 2021, 2:28 p.m.
©
BY-NC-ND(4.0)
转发文档
Collection documents
Last
Next
手机扫码
Copy link
手机扫一扫转发分享
Copy link
Markdown文件
share
link
type
password
Update password