背景

单线程监听端口+读写socket+处理数据,如果接收了很多请求,每个请求状态不一样,处理起来就会非常复杂。

IO多路复用就是解决的这个问题,单线程可以把监听端口与监听请求状态的事情委托给IO多路复用模型,有消息的时候,模型再通知线程处理,同时告知线程这个消息的类型。

所述模型均由操作系统实现。

select

最早的一种IO多路复用模型

基本逻辑

1.主线程维护一个fd_set,fd_set里包含需要监听的fd,形式为bitmap,内存连续的线性表

2.每次主线程将fd_set交给select函数,select函数将fd_set从用户态拷贝进内核态,并监听

3.超时/用户设置立即返回/有消息的时候,select函数将内核态fd_set拷贝进用户态,并返回给主线程

4.主线程遍历fd_set,找到有消息的fd,处理消息

存在的问题

1.很明显,如果我的fd_set巨大,但有消息的fd很少,我就花了好多时间在遍历fd_set上

2.同样的,如果我很频繁调用select,但每次有消息的fd很少,fd_set就会反复在用户态与内核态之间转换

3.监听的socket数量有1024个的硬限制,修改限制需要重新编译os内核

4.由于select函数直接修改传入的fd_set,所以我们还要自己记一下现在手上有哪些fd,比较麻烦

优点

跨平台

poll

select改进版,但没啥太大进步

基本逻辑

1.主线程维护一个struct pollfd数组,数组里包含需要监听的fd、监听读or写or异常、监听结果

2.调用poll的时候,数组被拷贝进内核态,并且转化为walk链表。(链表可以在拷贝回用户态时只拷贝有变动的节点,减少拷贝量)

其他的与select类似,等于就是解决了select的问题4

存在的问题

1.同select的问题1与问题2

2.不跨平台,Linux实现

优点

1.有个数据结构存储fd(解决了select问题4)

2.能改socket文件数量上限

如果觉得我的文章对你有用,请随意赞赏