epoll的过程:epoll_create、epoll_ctl、epoll_wait、内核往双向链表增加节点

文章目录

1.int epoll_create(int size) //size: >0(size大于0就行)

①创建了一个eventpoll结构对象,被系统保存到某个位置;

在这里插入图片描述

②rbr成员被初始化成指向一颗红黑树的根,有了这个根,就可以向红黑树中插入节点,或者说插入数据了【有了一个红黑树】;

在这里插入图片描述

③rdlist成员被初始化成指向一个双向链表的根【有了这个根,就可以向双向链表中插入节点,或者说插入数据了】;

在这里插入图片描述

2.int epoll_ctl(int efpd,int op,int sockid,struct epoll_event *event);

1)格式:

int epoll_ctl(int efpd,int op,int sockid,struct epoll_event *event);

2)功能:

把一个socket以及这个socket相关的事件添加到这个epoll对象描述符中去,目的就是通过这个epoll对象来监视这个socket【客户端的TCP连接】上数据的来往情况;(注意:efpd:epoll_create()返回的epoll对象描述符;)

3)参数说明:

①参数epfd:从epoll_create返回的epoll对象描述符

②②参数op:一个操作类型,可以理解为一个数字,添加/删除/修改 ,对应数字是1,2,3, EPOLL_CTL_ADD, EPOLL_CTL_DEL ,EPOLL_CTL_MOD
EPOLL_CTL_ADD添加事件:等于你往红黑树上添加一个节点,每个客户端连入服务器后,服务器都会产生 一个对应的socket,每个连接这个socket值都不重复所以,这个socket就作为红黑树中的key把这个节点添加到红黑树上去;
EPOLL_CTL_MOD:修改事件;你 用了EPOLL_CTL_ADD把节点添加到红黑树上之后,才存在修改;
EPOLL_CTL_DEL:是从红黑树上把这个节点干掉;这会导致这个socket【这个tcp链接】上无法收到任何系统通知事件(不是关闭这个TCP连接),所以这一项只有需要用时才用;

③参数sockid:一个TCP连接。添加事件(往红黑树中增加节点)时,就可以通过sockid作为key往红黑树中增加节点

④event:向epoll_ctl函数传递信息。如要增加事件信息,就可以通过event参数讲具体事件传递进epoll_ctl函数。这里包括的是 一些事件信息;EPOLL_CTL_ADD和EPOLL_CTL_MOD都要用到这个event参数里边的事件信息;

4)如果事件是EPOLL_CTL_ADD

执行函数顺序如下:

①先在红黑树上找,根据key来找,也就是这个sockid,找的速度会非常快

在这里插入图片描述

②生成了一个epitem对象,大家注意这个结构epitem,这个结构对象,其实就是红黑的一个节点,也就是说,红黑树的每个节点都是 一个epitem对象;

在这里插入图片描述
节点的数据结构如下
在这里插入图片描述

③把socket(TCP连接)保存到节点中;

在这里插入图片描述

④我们要增加的事件也保存到节点中;

在这里插入图片描述

⑤把这个节点插入到红黑树中去

在这里插入图片描述

5)如果事件是EPOLL_CTL_MOD

执行函数顺序如下:

1)先在红黑树上找,根据key来找,也就是这个sockid,找的速度会非常快

在这里插入图片描述

2)红黑树上有该节点,则修改对应的事件

在这里插入图片描述

6)如果事件是EPOLL_CTL_DEL

执行函数顺序如下:

1)先在红黑树上找,根据key来找,也就是这个sockid,找的速度会非常快

在这里插入图片描述

2)从红黑树上把这个节点干掉

在这里插入图片描述

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

1)格式:

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

2)功能:(到双向链表中去取相关的事件通知)

阻塞一小段时间并等待事件发生,返回事件集合,也就是获取内核的事件通知;说白了就是遍历这个双向链表,把这个双向链表里边的节点数据拷贝出去,拷贝完毕的就从双向链表里移除该节点。因为双向链表里记录的是所有事件的socket【TCP连接】;

3)函数执行

(1)这个while用来等待一定的时间【在这段时间内,发生事件的TCP连接,相关的节点,会被操作系统扔到双向链表去【当然这个节点同时也在红黑树中呢】】
	while (ep->rdnum == 0 && timeout != 0) {

		ep->waiting = 1;
		if (timeout > 0) {

			struct timespec deadline;

			clock_gettime(CLOCK_REALTIME, &deadline);
			if (timeout >= 1000) {
				int sec;
				sec = timeout / 1000;
				deadline.tv_sec += sec;
				timeout -= sec * 1000;
			}

			deadline.tv_nsec += timeout * 1000000;

			if (deadline.tv_nsec >= 1000000000) {
				deadline.tv_sec++;
				deadline.tv_nsec -= 1000000000;
			}

			int ret = pthread_cond_timedwait(&ep->cond, &ep->cdmtx, &deadline);
			if (ret && ret != ETIMEDOUT) {
				nty_trace_epoll("pthread_cond_timewait\n");
				
				pthread_mutex_unlock(&ep->cdmtx);
				
				return -1;
			}
			timeout = 0;
		} else if (timeout < 0) {

			int ret = pthread_cond_wait(&ep->cond, &ep->cdmtx);
			if (ret) {
				nty_trace_epoll("pthread_cond_wait\n");
				pthread_mutex_unlock(&ep->cdmtx);

				return -1;
			}
		}
		ep->waiting = 0; 

	}

	pthread_mutex_unlock(&ep->cdmtx);
(2)取得事件的数量

在这里插入图片描述

(3)每次都从双向链表头取得 一个一个的节点

在这里插入图片描述

(4)把这个节点从双向链表中删除【但这并不影响这个节点依旧在红黑树中】

在这里插入图片描述

(5)这是个标记,标记这个节点【这个节点本身是已经在红黑树中】已经不在双向链表中;

在这里插入图片描述

(6)把事件标记信息拷贝出来;拷贝到提供的events参数中

在这里插入图片描述

(7)返回 实际 发生事件的 tcp连接的数目;

在这里插入图片描述

4.内核往双向链表增加节点

1)下面四个事件会触发操作系统把节点插入双向链表:

a)客户端完成三路握手,操作系统会向双向链表中插入节点,这时服务器要调用accept()函数把该连接从已完成队列中取走;
b)当客户端关闭连接,操作系统会向双向链表中插入节点,这时服务器也要调用close()关闭对应的socket;
c)客户端发送数据来的,操作系统回想双向链表中插入节点,服务器要调用read(),recv()函数来收数据;
d)当可以发送数据时,操作系统回想双向链表中插入节点,服务武器可以调用send(),write()向客户端发送数据。

2)当上面这四种情况之一发生时,操作系统会调用epoll_event_callback函数向双向链表中插入一个节点。

①使用RB_FIND在红黑树中寻找节点

在这里插入图片描述

②如果节点已经在双向链表中,则叠加事件后返回

这段做法存疑,因为epi->event.events事件原本是操作系统关注的事情,实际上操作系统内核是要判断该事件是否是程序关注的事件,如果是,才向双向链表插入数据,待商榷

在这里插入图片描述

③epi->rdy=1,把该节点是否在双向链表中的标记设置为1(表示在双向链表中)

在这里插入图片描述

④执行代码LIST_INSERT_HEAD把这个节点链入双向链表的表头位置

在这里插入图片描述

⑤双向链表中的节点数量加1,刚才研究epoll_wait()的时候,从双向链表中把这个节点取走的时候,这个数量减了1

另外,epoll_wait函数,如果双向链表有数据,可能不需要等待参数timeout中指定的时间,可能epoll_wait会立即返回;如果没有数据,才会等待timeout这么长的时间。

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值