【I/O多路复用】epoll系统调用的ET(Edge Trigger)模式

本文介绍了epoll的ET(Edge Trigger)模式,对比了ET模式与LT模式的区别,强调了ET模式的高效特性。在ET模式下,epoll_wait仅在事件发生时通知一次,需要配合非阻塞IO使用以确保所有数据被正确处理。文章通过阻塞和非阻塞模式的代码示例,展示了如何在ET模式下实现高效的数据读取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【1】什么是epoll的LT和ET模式

epoll对文件描述符的操作有两种模式
LT(LevelTigger)电平触发模式ET (EdgeTrigger, 边沿触发)模式

LT模式是默认的工作模式,这种模式下epoll相当于一 个效率较高的poll.
当往epoll内核事件表中注册一个文件描述符上的EPOLET事件时,epoll将以ET模式来操作该文件描述符。ET模式是epoll的高效工作模式。

对于采用LT工作模式的文件描述符,当epollwait检测到其上有事件发生并将此事件通知应用程序后,应用程序可以不立即处理该事件这样,当应用程序下一次调用epoll wait时,epoll wait 还会再次向应用程序通告此事件,直到该事件被处理。
对于采用ET工作模式的文件描述符,当epollwait检测到其上有事件发生并将此事件通知应用程序后,应用程序必须立即处理该事件,因为后续的epollwait调用将不再向应用程序通知这一事件

可见,ET模式在很大程度上降低了同一个epoll事件被重复触发的次数。因此ET模式效率要比LT模式高。

poll的LT模式代码可以参考我的前一个博客
【I/O多路复用】epoll系统调用(默认LT模式)

【2】ET的阻塞模式代码示例

我们通过代码来看ET模式下阻塞模式的缺点

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>

#define MAXFD 10

//向内核事件表epfd 中添加 新事件的文件描述符fd
void epoll_add(int epfd, int fd)
{
   
   
	// 设置epoll_event的结构成员 
	struct epoll_event ev;
	//=========================================
	ev.events = EPOLLIN|EPOLLET;//或上EPOLLET
	//=========================================
	ev.data.fd = fd;

	//EPOLL_CTL_ADD添加新事件及描述符到内核事件表
	if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
	{
   
   
		perror("epoll_ctl add error\n");
	}
}

void epoll_del(int epfd, int fd)
{
   
   
	//从内核事件表中移除fd
	if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) == -1)
	{
   
   
		perror("epoll_ctl del error\n");
	}
}

int create_sockfd();

int main()
{
   
   
	int sockfd = create_sockfd();
	assert(sockfd != -1);

	//创建内核事件表 
	int epfd = epoll_create(MAXFD);
	assert(epfd != -1);

	// 设置epoll_event的结构成员
	struct epoll_event ev;
	ev.data.fd = sockfd;
	ev.events = EPOLLIN;
	epoll_add(epfd, sockfd);

	// 定义events数组存放就绪描述符
	struct epoll_event events[MAXFD];

	while (1)
	{
   
      
		/* 
		epoll_wait返回的是前n个已经全就绪的文件描述符,
		那么我们不用全部遍历,只遍历前n个就可以
		超时时间设置为5秒
		*/
		int n = epoll_wait(epfd, events, MAXFD, 5000);

		//  epoll_wait() 调用失败
		if (n == -1)
		{
   
   
			perror("epoll wait error!\n");
		}
		else if (n == 0)
		{
   
   
			printf("time out!\n");
		}

		// 只遍历前n个,因为内核已告诉我们前n个有就绪事件
		else
		{
   
    
			int i = 0;
			for (; i < n; ++i)
			{
   
   
				int fd = events[i].data.fd;
				if (fd == -1)
				{
   
   
					continue;
				}

				// events 为内核为我们返回的就绪事件 
				if (events[i].events & EPOLLIN)
				{
   
   
					if (fd == sockfd)
					{
   
   
						struct sockaddr_in caddr;
						int len = sizeof(caddr);
						
						
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值