epoll是什么

epoll是一种I/O多路复用技术的一种,相比于pollselect有改进。

epoll的优点有以下:

  • 没有最大并发连接的限制,可打开文件数量远大于$2^{11}$
  • epoll不在乎连接总数,只和当前「活跃」的连接数量相关,因此相比于pollselect,效率明显提升
  • epoll使用了「共享内存」,因此省略了「内存拷贝」,进一步提升了效率

内核空间与用户空间

  • 内核空间是操作系统内核运行的区域,包含了操作系统内核代码、数据结构和设备驱动程序等

  • 用户空间是用户应用程序运行的区域,包括用户应用程序代码、数据和堆栈等

    空间分配

以Linux操作系统为例,将最高的1G分配给内核空间,剩余3G分配给用户空间。

而每个进程可以通过系统调用进入内核,因此Linux内核由系统内所有进程共享,每个进程拥有4G虚拟空间。

为什么要区分内核空间与用户空间

CPU指令中的部分指令很危险,如果错用会导致系统崩溃。因此将指令分级,部分只允许操作系统使用。

内核态与用户态

  • 当进程/线程运行于内核中是内核态;运行于用户空间中是用户态
  • 内核态下,CPU可以执行任何指令/运行的代码不受限制/自由访问地址/端口
  • 用户态下,代码收到CPU很多检查,例如只能访问部分空间

在这里插入图片描述

epoll函数

epoll主要包含三个函数epoll_create/epoll_ctl/epoll_event

包含这些函数的头文件为<sys/epoll.h>

fd(File descriptor)

fd是指文件描述符,是一个非负整数,本质上是一个索引值,类似一个地址,能直接获取某个文件。

什么时候拿到fd

当打开一个文件时,内核向进程返回一个文件描述符,后续打开这个文件则只需要用文件描述符标识该文件,作为参数传进read/write

fd的范围

0/1/2这3个值有特殊含义,分别是标准输入/标准输出/标准错误。

文件描述符的范围是[0,OPEN_MAX-1],代表默认最多可以打开多少个文件。

ulimit -n
256

使用ulimit -n命令查询得到256,说明同时最多可以打开256个文件。

epoll_create

int epoll_create(int size);

epoll_create函数是用来创建epoll文件描述符,用于后续的epoll操作。

img

epoll_ctl

int epoll_ctl(int epfd, int op, int fd, struct epoll_event &event);

epoll_ctl函数是用于增加、删除、修改epoll事件的函数。epoll事件存储于内核epoll结构体红黑树中。

epfd: epoll文件描述符
op: 操作码
EPOLL_CTL_ADD: 插入事件
EPOLL_CTL_DEL: 删除事件
EPOLL_CTL_MOD: 修改事件
fd: 事件绑定的套接字文件描述符
events: 事件结构体
返回值:0/-1(成功/失败)
img

epoll struct epoll_event

#include <sys/epoll.h>

struct epoll_event {
	uint32_t events; // epoll事件
	epoll_data_t data;
};
typedef union epoll_data {
	void *ptr;
	int fd;
	uint32_t u32;
	uint64_t u64;
} epoll_data_t;

epoll事件列表

头文件:<sys/epoll.h>
 
enum EPOLL_EVENTS
{
 EPOLLIN = 0x001, //读事件
 EPOLLPRI = 0x002,
 EPOLLOUT = 0x004, //写事件
 EPOLLRDNORM = 0x040,
 EPOLLRDBAND = 0x080,
 EPOLLWRNORM = 0x100,
 EPOLLWRBAND = 0x200,
 EPOLLMSG = 0x400,
 EPOLLERR = 0x008, //出错事件
 EPOLLHUP = 0x010, //出错事件
 EPOLLRDHUP = 0x2000,
 EPOLLEXCLUSIVE = 1u << 28,
 EPOLLWAKEUP = 1u << 29,
 EPOLLONESHOT = 1u << 30,
 EPOLLET = 1u << 31 //边缘触发
};

epoll_wait函数

epoll_wait用于监听套接字事件,可以通过设置超时时间timeout来控制监听行为是阻塞模式还是超时模式。

#include <sys/epoll.h>

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

参数:
epfd: epoll文件描述符
events: epoll事件数组
maxevents: epoll事件数组长度
timeout: 超时时间
小于0: 一直等待
等于0: 立即返回
大于0: 等待超时时间返回,单位毫秒

返回值:
小于0: 出错
等于0: 超时
大于0: 返回就绪事件个数

ET与LT

两种模式区别在于触发方式不同。LT模式(水平触发)会持续通知应用程序,直到所有事件被处理完毕;ET模式(边沿触发)只在事件发生变化的时侯通知应用程序,即只通知一次,不管事件是否已经被处理。

posted on 2024-03-26 12:31  lgats324  阅读(9)  评论(0编辑  收藏  举报