服务端
请求处理模型
- 单线程阻塞模型
- 多线程/进程模型
- 线程池模型
- 异步非阻塞模型
- 协程模型
异步非阻塞模型
epoll
epoll(event poll) 是 Linux 内核提供的一种高级 IO 多路复用机制,可以监听多个文件描述符上的事件,并将这些事件通知给应用程序,从而实现异步的 IO 操作。
epoll 监听的 fd(file descriptor)集合是常驻内核的,它有 3 个系统调用 (epoll_create, epoll_wait, epoll_ctl),通过 epoll_wait 可以多次监听同一个 fd 集合,只返回可读写那部分。
来自 ChatGPT
epoll 是 Linux 内核提供的一种高级 IO 多路复用机制,它可以同时监听多个文件描述符上的事件,并将这些事件通知给应用程序。与传统的 Select 和 Poll 机制相比,epoll 具有更高的性能和更好的可扩展性。
具体来说,epoll 通过以下几个关键部分来实现 IO 多路复用:
- epoll_create:创建一个 epoll 对象,并返回其对应的文件描述符。
- epoll_ctl:向 epoll 对象中添加或删除指定的文件描述符,以及设置相应的事件类型等参数。
- epoll_wait:等待指定文件描述符上的事件发生,并将这些事件收集起来返回给应用程序。
在使用 epoll 进行 IO 多路复用时,通常采取如下的处理流程:
- 创建 epoll 对象,并将需要监听的文件描述符添加到 epoll 的事件列表中。
- 使用 epoll_wait 等待事件的发生,当某个文件描述符上有事件发生时,就会触发 epoll_wait 返回。
- 根据事件类型进行相应的处理。如果是可读事件,则读取数据并进行处理;如果是可写事件,则进行写操作。
- 处理完毕后,将文件描述符从 epoll 的事件列表中删除。
需要注意的是,epoll 机制支持三种事件触发模式,包括边缘触发(Edge Triggered)、水平触发(Level Triggered)和一次性触发(One-Shot)。其中,边缘触发模式是最高效的一种模式,它只在文件描述符状态发生变化时才会通知应用程序;而水平触发和一次性触发模式需要更多的系统调用,因此相对较慢。
总的来说,epoll 机制具有高效、可扩展、灵活等优点,在高并发场景下被广泛使用。
epoll 如何通知应用程序
在 epoll 机制中,当 I/O 事件发生时,应用程序通过调用 epoll_wait 函数等待事件的发生。该函数会阻塞当前线程,直到有事件发生或者超时,然后将所有已经就绪的文件描述符加入到一个由 epoll_event 结构体组成的数组中,最后返回数组中的事件数量。
每个 epoll_event 结构体包含了一个就绪的文件描述符和该文件描述符上发生的事件类型。应用程序随后可以遍历这个数组,并根据文件描述符和其对应的事件类型进行相应的处理(如读取数据、写入数据等)。
需要注意的是,在边缘触发模式下,如果有多个事件同时发生,epoll_wait 只会返回一次通知。因此,应用程序在处理完某个文件描述符上的事件后,需要重新调用 epoll_wait 函数获取下一轮事件通知。
总之,epoll 机制的通知方式是通过将就绪的文件描述符和相应的事件类型打包成一个结构体,并返回给应用程序,从而实现了高效、可扩展、高并发的 IO 处理。
select
select 只有一个系统调用,每次要监听都要将其从用户态传到内核,有事件时返回整个集合。
来自 ChatGPT
select 是一种基于 IO 多路复用的系统调用,它可以同时监听多个文件描述符上的事件,并在其中有事件发生时通知应用程序进行处理。select 机制主要由以下三个部分组成:
- fd_set 数据结构:用于存储需要监听的文件描述符集合。
- select 函数:用于将需要监听的文件描述符集合传递给内核,以及等待事件的发生并返回事件列表。
- 相应的文件操作函数:例如 read、write 等,用于对文件描述符执行相应的 IO 操作。
在使用 select 进行 IO 多路复用时,通常采取如下的处理流程:
- 创建 fd_set 数据结构,并将需要监听的文件描述符添加到该数据结构中。
- 调用 select 函数等待事件的发生。当某个文件描述符上有事件发生时,就会触发 select 返回。
- 使用相应的文件操作函数对事件进行处理。如果是可读事件,则读取数据并进行相应的处理;如果是可写事件,则进行写操作。
- 循环执行上述过程,直到关闭连接或出现异常。
需要注意的是,在 select 模式下,文件描述符数量受到限制,通常不能超过系统默认值(例如 1024)。此外,在高并发情况下,select 的效率较低,因为每次都需要对所有监控的文件描述符进行扫描,无法有效利用 CPU 和内存等资源。因此,在实现高并发服务器时,通常采用更为高效的机制,如 epoll 和 kqueue 等。