17. IO复用之epoll触发模式

该博客介绍了epoll的两种触发模式——水平触发和边沿触发。水平触发在缓冲区有数据时会持续触发,直至数据读写完成;而边沿触发仅在缓冲区状态改变时触发一次。文章通过实例代码对比了两种模式的行为,并指出通常情况下,水平触发模式已足够使用。

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


epoll有两种触发模式 : 水平触发边沿触发. 默认为水平触发模式.


水平触发

什么叫做水平触发呢? IO大都有缓冲区, 当缓冲区里面只要有数据时就会触发水平模式,直到将缓冲的数据读写结束才不会触发水平模式.

举个栗子 : 当我们现在的读缓冲区有1024字节的数据而我们每次都只能读一个字节, 那么一次读操作后缓冲区还有1023字节, 此时又继续触发水平模式继续读, 直到1024字节读完才不会触发水平模式.

因为默认是水平默认, 所以我们现在做的实验并容易引起大家的感觉. 实验代码只将服务端的buf[1024]改为了buf[2] ,完整代码epoll_default.c

客户端发送一串字符后也收到了完整的字符串. 运行结果 :

在这里插入图片描述

边沿触发

什么叫边沿触发呢? IO大都有缓冲区, 缓冲区发生变化才会触发边沿模式.

举个栗子 : 我们每次都只能读一个字节. 当现在的读缓冲区增加到了1024字节的数据, 缓冲区有改变了那么触发边沿模式读一个字节, 操作后缓冲区还有1023字节. 但是现在缓冲区没有变化了, 所以不再触发边沿模式, 剩下的1023字节只有留在缓冲区中.

通过设置event事件为EPOLLET才开启边沿触发.

只将服务端的buf[1024]改为了buf[2]并设置了EPOLLET.


完整代码 epoll_ET.c.

void doService(int servicefd)
{
    char buf[2];	// 设置为2

    while(1)
    {
	eventNum = epoll_wait(epfd, evts, EPOLL_MAX, -1);
	if(eventNum == 0)
	    continue;
	else if(eventNum < 0)
	    EXIT("epoll_wait");
	for(int i = 0; i < eventNum; i++)
	{
	    if(evts[i].data.fd == servicefd && (evts[i].events &EPOLLIN))
	    {
		clientfd = Accept(servicefd, NULL, NULL);
		event.events = EPOLLIN | EPOLLET;	// 设置为边沿触发
		event.data.fd = clientfd;
		epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &event);
	    }
	    else if(evts[i].events & EPOLLIN)
	    {
		n = recv(evts[i].data.fd, buf, sizeof(buf), 0);
		if(n <= 0)
		{
		    epoll_ctl(epfd, EPOLL_CTL_DEL, evts[i].data.fd, NULL);
		    close(evts[i].data.fd);
		    fprintf(stderr, "peer close\n");
		}
		send(evts[i].data.fd, buf, n, 0);
	    }
	}
    }
}

运行结果 :

在这里插入图片描述

可以看出发送了1234567890但是一次客户端只会发送两个字节过来. 再看当客户端没有接收到所有的字符后关闭服务端也会被意外的关闭, 因为客户端发送了RET段. 当然这只是代码的问题, 大家可以自行修改.

在这里插入图片描述


注意

现在没有证实过边沿触发和水平触发哪一个更好, 一般我们都采用默认的水平触发就足够了.


总结

理解什么是水平触发, 什么是边沿触发.

  • 水平触发
  • 边沿触发
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值