请选择 进入手机版 | 继续访问电脑版

「网络」「操作系统」详解select、poll、epoll

[复制链接]
查看: 1696|回复: 3
avatar

630

主题

630

帖子

1920

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
1920
online_admin 发表于 2021-7-22 20:26:51 | 显示全部楼层 |阅读模式
看到这张图你能够完全理解吗。

相关视频讲解

基于linux epoll网络编程细节处理:「链接」

网路io底层epoll:「链接」

提升服务器底层性能,异步解决方案:「链接」

1.多路复用的意思:多路复用的意思,就是在任何一路 I/O 有“事件”发生的情况下,通知应用程序去处理相应的 I/O 事件,这样我们的程序就变成了“多面手”,在同一时刻仿佛可以处理多个 I/O 事件。

2.应用条件:


  • 标准输入文件描述符准备好可以读。
  • 监听套接字准备好,新的连接已经建立成功。
  • 已连接套接字准备好可以写。
  • 如果一个 I/O 事件等待超过了 10 秒,发生了超时事件。
3.中断的概念:

在cpu运行着进程A时,进程B发起一个中断请求IRQ,中断处理程序进行处理请求,将进程A挂起,然后运行进程B。

中断的过程:将当前运行的进程的运行信息保存到该进程的描述符。根据进程描述符的内核态堆栈指针切换到内核态。根据来到的IRQ在中断表里面查找所属的中断处理程序。运行该中断处理程序。(看似是进程执行的中断,但和进程没什么关系)

4.硬中断的概念:

对于计算机硬件的,一般来说是与当时CPU请求是异步的(没关系的),比如网关来了一个报文,

5.软中断的理解:

CPU在执行一段代码段是 遇到问题,进行中断,由用户态切换到内核态。

6.每次中断都有其对应的中断处理程序。

7每个进程都在用户态和内核态拥有一个堆栈。

8.为什么要有两种状态(内核态、用户态)

内核态和用户态的”权限不同“。防止每个程序都分配过多资源。用户态的进程能够访问的资源受到了极大的控制,而运行在内核态的进程可以“为所欲为”。

一个进程可以运行在用户态也可以运行在内核态,那它们之间肯定存在用户态和内核态切换的过程。

打一个比方:C库接口malloc申请动态内存,malloc的实现内部最终还是会调用brk()或者mmap()系统调用来分配内存。

9.从用户态到内核态切换可以通过三种方式:


  • 系统调用,这个上面已经讲解过了,在我公众号之前的文章也有讲解过。其实系统调用本身就是中断,但是软件中断,跟硬中断不同。
  • 异常:如果当前进程运行在用户态,如果这个时候发生了异常事件,就会触发切换。例如:缺页异常。
  • 外设中断:当外设完成用户的请求时,会向CPU发送中断信号。
10.socket的小demo



11.socket底层逻辑图


12.阻塞模式下的情况




(1)要传输的数据大于 输出缓冲区的大小,需要分开传输,还没传输的挂起。

(2)输出缓冲区TCP正在输出别的数据,需要TCP释放输出缓冲区才能写。



(1)如果输入缓存区没有数据,则系统调用的方法挂起。

(2)缓冲区数据太多,每次read只能读一部分,需要一直慢慢读直到读完

13.非阻塞模式下

文章福利 Linux后端开发网络底层原理知识学习提升 点击 正在跳转 获取,完善技术栈,内容知识点包括Linux,Nginx,ZeroMQ,MySQL,Redis,线程池,MongoDB,ZK,Linux内核,CDN,P2P,epoll,Docker,TCP/IP,协程,DPDK等等。




(1)如果向输出缓冲区写的数据太多了 ,分批发送,但是会马上告诉你发送了多少。

(2)如果空间为0,会马上告诉你缓冲区满了,由上次程序决定怎么做。(而阻塞则会一直挂起,等待缓冲区释放)

14.进程进行用户态到内核态的切换过程:

  1.从当前进程的描述符中提取其内核栈的ss0及esp0信息。

  2.使用ss0和esp0指向的内核栈将当前进程的cs,eip,eflags,ss,esp信息保存起来,这个过程也完成了由用户栈到内核栈的切换过程,同时保存了z暂停执行的程序的下一条指令。

  3.将先前由中断向量检索得到的中断处理程序的cs,eip信息装入相应的寄存器,开始执行中断处理程序,这时就转到了内核态的程序执行了。

15.Linux的一切都是文件fd。

16.select函数

    #include <sys/select.h>       int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout);
1)maxfdpl   最大有效位。(因为fd_set是以bitmap来保存数据的 linux默认1024位bitmap 最大有效位之后不需要检查)

2)fd_set *readset   可读文件描述符集

3)fd_set *writeset   可写文件描述符集

4)fd_set *exceptset   异常文件描述符集

5)timeout  超时时间

Linux select函数的宏

#include <sys/select.h>   int FD_ZERO(int fd, fd_set *fdset);  //将描述符集全部置0int FD_CLR(int fd, fd_set *fdset);   //int FD_SET(int fd, fd_set *fd_set);   //将某个位置位int FD_ISSET(int fd, fd_set *fdset); //检查某个位是否被置位
select函数缺点:

1)固定文件描述符1024位的bitmap,请求过大则无法描述,有大小限制

2)fd_set不可重用,每次都有重新置位

3)有用户态到内核态切换的开销

4)每次函数返回都需要O(n)的时间进行遍历

17.poll函数

我们将select函数的bitmap结构的fd_set变为 自己实现的pollfd




使用链表来进行文件描述,不存在大小限制问题。


18.epoll函数


19.同步调用、异步调用:

同步:B来向A拿取数据,B一直等到A正确交付数据。

异步:B来向A拿取数据,B见A还在准备则返回 进行自己的事情。

20.阻塞、非阻塞

A向B拿数据,C也向A要数据,C要等待 则是阻塞。

A向B拿数据,C也向A要数据,A同时服务B C 则是非阻塞。

同步与异步


  • 同步: 同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回。
  • 异步: 异步就是发起一个调用后,立刻得到被调用者的回应表示已接收到请求,但是被调用者并没有返回结果,此时我们可以处理其他的请求,被调用者通常依靠事件,回调等机制来通知调用者其返回结果。
同步和异步的区别最大在于异步的话调用者不需要等待处理结果,被调用者会通过回调等机制来通知调用者其返回结果。

阻塞和非阻塞


  • 阻塞: 阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。
  • 非阻塞: 非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。
21.网络通信例子

服务端


客户端



我们可以看到服务端有2个方法 accept和read都在阻塞,这就是我们的BIO(同步阻塞I/O模式)

优化:我们可以使用多线程、线程池等来优化,关键是有很多不活跃的线程时,占用资源过多,上下文切换过多。

22.使用NIO优化通信例子(服务器端 客户端无所谓)




23.windows的NIO是select linux的NIO底层是eqpoll。

Redis的NIO是epoll,只能在Linux环境运行,但是有win版本,是大神修改了redis代码。
回复

使用道具 举报

avatar

0

主题

4

帖子

18

积分

新手上路

Rank: 1

积分
18
在线会员 发表于 2021-7-22 20:27:34 | 显示全部楼层
转发了
回复

使用道具 举报

avatar

0

主题

6

帖子

22

积分

新手上路

Rank: 1

积分
22
在线会员 发表于 2021-7-22 20:27:41 | 显示全部楼层
转发了
回复

使用道具 举报

avatar

0

主题

6

帖子

22

积分

新手上路

Rank: 1

积分
22
在线会员 发表于 2021-7-22 20:27:56 | 显示全部楼层
转发了
回复

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies

本版积分规则

logo
  • 反馈建议:893566502@qq.com
  • 工作时间:周一到周五 10:00-19:00

关注我们

  • wx