Linux IO 多路复用

Linux IO 多路复用

简介

linux io 多路复用是用来实现单进程同时处理多个io请求的有效方法。

linux的io多路复用主要有以下3中方式:

  • select

  • poll

  • epoll

select

​ select函数监视的文件描述符有三类,readfds,writefds,exceptfds。调用后函数会阻塞,直到有描述符就绪(有数据读、写、或者有except),或者超时(timeout指定时间,如果立即返回设置null),函数返回。当select函数返回后,可以通过便利fdset,

1
2
3
4
5
6
7
8
// select
int select(
    int n,                   //被监听的描述符的最大值+1
    fd_set *readfds,         //被监听的读事件fd集合
    fd_set *writefds,        //被监听的写事件fd集合
    fd_set *exceptfds,       //被监听的异常事件fd集合 
    struct timeval *timeout  //监听的超时时间
);

select 实现方式:

  1. 用户进程将要监听的fd放到一个文件描述符集合fd_set中,该fd_set是一个BitsMap,一次最多可监听1024个fd;

  2. 用户进程调用select() 函数将fd_set拷贝到内核;

  3. 内核遍历各fd_set,检查是否有网络事件产生;

  4. 内核当检查到有事件产生后,将此fd标记为可读或可写;

  5. 内核把fd_set拷贝回用户态里;

  6. 用户进程遍历fd_set, 找到可读或可写的fd,然后再对其处理。

select:效率低,性能不太好。不能解决大量并发请求的问题。

poll

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int poll(
    struct pollfd *fds,    //被监听描述符和相应的事件
    unsigned int nfds,     //被监听描述符的个数
    int timeout            //超时
);
struct pollfd{
  int fd;
  short events;
  short revents;
};
  • poll基本原理和selec相同;
  • 不同之处在于:不用 BitsMap而是链表来存储fd_set, 因此一次监听的fd数量不会受到bitsmap的限制;

epoll

  • epoll_create: 创建epoll池子。

  • epoll_ctl:向epoll注册事件。告诉内核epoll关心哪些文件,让内核没有健忘症。

  • epoll_wait:等待就绪事件的到来。专门等哪些文件,第2个参数 是输出参数,包含满足的fd,不需要再遍历所有的fd文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
int s = socket(AF_INET, SOCK_STREAM, 0);
bind(s, ...);
listen(s, ...)

int epfd = epoll_create(...);
epoll_ctl(epfd, ...); //将所有需要监听的socket添加到epfd中
epoll_ctl(epfd, ...); 
...

while(1) {
    int n = epoll_wait(...);
    for(接收到数据的socket){
        //处理
    }
}

ET和LT

epoll 支持两种事件触发模式,分别是边缘触发(edge-triggered,ET水平触发(level-triggered,LT

  • 使用边缘触发模式(EdgeTriger)时,当被监控的 Socket 描述符上有可读事件发生时,服务器端只会从 epoll_wait 中苏醒一次,即使进程没有调用 read 函数从内核读取数据,也依然只苏醒一次,因此我们程序要保证一次性将内核缓冲区的数据读取完;
  • 使用水平触发模式时,当被监控的 Socket 上有可读事件发生时,服务器端不断地从 epoll_wait 中苏醒,直到内核缓冲区数据被 read 函数读完才结束,目的是告诉我们有数据需要读取;

signal IO

目前在linux中很少被用到,Linux内核某个IO事件ready,通过kill出一个signal,应用程序在signal IO上绑定处理函数。

kernel发现设备读写事件变化,调用一个 kill fa_sync ,应用程序绑定signal_io上的事件。

参考

  1. 9.2 I/O 多路复用:select/poll/epoll | 小林coding

  2. https://zh.wikipedia.org/zh-cn/Epoll

  3. Linux下的I/O复用与epoll详解 - junren - 博客园

updatedupdated2024-05-102024-05-10