IO多路复用之select、poll、epoll学习入门

  • 看视频学习:https://www.bilibili.com/video/BV1qJ411w7du?from=search&seid=17786017183453179660
  • 知乎 epoll讲解: https://zhuanlan.zhihu.com/p/63179839

网卡接收信息

网卡接收到信息会复制到内存中,然后产生中断,操作系统接着执行中断程序,如下图。关于将数据由哪一个socket接收是由端口决定的。
在这里插入图片描述

文件描述符

先描述一下文件描述符吧。先看一张图(别人的)。
在这里插入图片描述
linux希望能够实现一切都是类似文件操作。

在一个线程创建时,就会有一个pcb进程控制块,记录各种信息,其中包括files_struct*指针,指向一个struct_file结构体对象,里面有包含关于一个线程用到的所有的文件引用地址,它们是用一个fd_array存储,那么这个数组的下标就是我们说的文件描述符,这也是为什么很多通过文件描述符是整型,利用文件描述符 可以快速的找到一个文件进行操作。

那么你可能平时使用c操作文件时用的是fopen,返回一个File* 类型,是不是有点熟悉的感觉?fd_array中保存的就是这个类型,也就是说它和文件描述符的区别就是,一个是索引,一个是具体的数组[索引]对应File* 类型的值。而c语言中的open函数则是返回文件描述符,文件描述符和File*类型的值是可以相互转化的。open与fopen区别 相关描述可以看:https://blog.csdn.net/t_x_l_/article/details/72123669 的介绍。

io多路复用模型之select

内存分为用户态和内核态,那我们平时程序是跑在用户态的,程序发起一个监听的accept事件时,在内存中就会产生一个socket对象,详细的了解可以查看(盗图的):https://zhuanlan.zhihu.com/p/63179839。

当进程执行到创建socket的语句时,操作系统会创建一个由文件系统管理的socket对象(如下图),创建时返回的值就是对应的文件描述符,拿着文件描述符就相当拿着指向这个socket的指针。这个socket对象包含了发送缓冲区、接收缓冲区、等待队列等成员。等待队列是个非常重要的结构,它指向所有需要等待该socket事件的进程。

在这里插入图片描述
在这里插入图片描述
看上面的代码,显示通过accept在内存中建立了socket,我们得到每个socket的文件描述符,保存在fds数组中,我们再利用一个叫 rset 的值去标记,这个rset思想有的类似一个十进制数的二进制位,如果fds[i] 为5,那么就让第4 个位为1(从0开始).

接着,程序调用select把这个rset传给内核,让内核对rset中为1的位的对应的fd_array中记录的 指向的 socket进行轮询(让内核去做轮询速度会更快),访问看有没有数据,如果都没,那么内核的selet进入阻塞,直到某个socket来了数据,这时候可以就会唤醒系统 select,select会遍历所有的rset 指定的socke,若有数据,就会对对应的位置1,最后 返回到应用程序向下执行代码。那么程序中继续往下执行,用户程序需要对 rset 的值进行对比,比如说,第4位原来为1,来了数据就变为0,那么进程到对应内核空间的接收缓冲区中去读取数据。

最后,用户程序再次调用select时,仍然需要去重置 rset。

IO多路复用 之 poll

在这里插入图片描述

poll引入了新的数据结构,pollfd,好处就是解决了原来select模型中的 bitmap大小限定最大为1024的问题(如果要更改更大的值,可修改某些配置),然后,我想到的是,如果select修改配置,轮询2000个socket,很耗内核的轮询时间,即使你用poll去监听2000个不是也很耗时。。

IO多路复用之epoll

先看大概的代码和图示。其实我不大明白accept部分为啥可以创建多个socket(因为java里面到了这一步是会阻塞的,除非设置了不阻塞)
在这里插入图片描述
epoll的改进之处很明显。首先引入了epoll_event结构体,然后event.data.fd是记录文件描述符,ev.events是关注的事件。最重要的是epoll.ctl,这个方法将ev变量放到 共享内存中,这样用户程序和内核的程序就不需要进行交换数据,故效率提升,另外每次都返回对应的已经接收到数据的文件描述符O(1),代替原来的再次遍历所有O(n)。epoll_wait就是类似select模型中的select.还有就是epoll使用通知机制,这样的好处是不需要去轮询遍历,比如当某个socket中数据可读,则触发这样的一个事件,通过这个事件将文件描述符添加到 rdlist(就绪队列)中。

视频中讲epoll是将有数据的socket的文件描述符重排,再返回有数据的socket的个数,这样直接遍历所有的已有数据的socket接收缓冲区,emmm,不是很确定,我看https://zhuanlan.zhihu.com/p/64746509上讲的,是把所有有消息的socket放到rdlist中,然后返回用户程序直接根据rdlist就行。。 。应该是知乎专栏说的对吧,不过知乎专栏没提到 共享内存 的使用,所以一开始看就很懵。

推荐阅读文章:https://www.jianshu.com/p/31cdfd6f5a48

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值