当前位置: 首页 > news >正文

工商营业执照注册网站wordpress qq快捷登录

工商营业执照注册网站,wordpress qq快捷登录,网络游戏免费加盟代理,电商排名前十名品牌目录 从epoll接口入手 创建epoll模型 用户告诉内核关心的事件 内核告诉用户就绪的事件 epoll的原理 整体思路 如何判断事件是否就绪 事件就绪后如何实现将节点插入就绪队列 从epoll接口入手 本篇文章从epoll的三个接口入手介绍epoll的具体工作原理 创建epoll模型 #in…

目录

从epoll接口入手

创建epoll模型

用户告诉内核关心的事件

内核告诉用户就绪的事件

epoll的原理

整体思路

如何判断事件是否就绪

事件就绪后如何实现将节点插入就绪队列


从epoll接口入手

本篇文章从epoll的三个接口入手介绍epoll的具体工作原理

创建epoll模型

#include <sys/epoll.h>
int epoll_create(int size);

创建一个epoll的句柄,从linux-2.6.8后,size参数是被忽略的,用完之后必须调用close关闭。

返回值实际上就是一个文件描述符

用户告诉内核关心的事件

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

 epoll作为多路转接的方案,依然要解决如何让操作系统知道用户关心哪些文件描述符的哪些事件的问题,这个接口解决的就是这个问题。epfd是epoll_create返回的文件描述符,op表示动作,用三个宏来表示。

EPOLL_CTL_ADD:注册新的 fd 到 epfd 中;
EPOLL_CTL_MOD:修改已经注册的 fd 的监听事件;
EPOLL_CTL_DEL:从 epfd 中删除一个 fd;

fd是用户关心的文件描述符,最后一个参数event告诉内核要监听fd上的哪些事件,再来看看epoll_event的结构

struct epoll_event
{uint32_t events;	/* Epoll events */epoll_data_t data;	/* User data variable */
} __EPOLL_PACKED;typedef union epoll_data
{void *ptr;int fd;uint32_t u32;uint64_t u64;
} epoll_data_t;

events是事件类型,有以下几个宏

EPOLLIN : 表示对应的文件描述符可以读 (包括对端 SOCKET 正常关闭);
EPOLLOUT : 表示对应的文件描述符可以写;
EPOLLPRI : 表示对应的文件描述符有紧急的数据可读 (这里应该表示有带外数据到来);
EPOLLERR : 表示对应的文件描述符发生错误;
EPOLLHUP : 表示对应的文件描述符被挂断;
EPOLLET : 将 EPOLL 设为边缘触发(Edge Triggered)模式, 这是相对于水平触发(Level Triggered)来说的.
EPOLLONESHOT:只监听一次事件, 当监听完这次事件之后, 如果还需要继续监听这个 socket 的话, 需要再次把这个 socket 加入到 EPOLL 队列里.

关于epoll_data这个结构,在写代码时还会细谈

内核告诉用户就绪的事件

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

epfd依然是epoll_create的返回值,events和maxevents确定了一个epoll_event的数组,这个数组包含了哪些文件描述符的哪些事件就绪的信息,timeout是超时时间,返回值与select和poll一样

为0表示超时返回;为-1表示有错误发生,并设置错误码errno;为正数表示在timeout时间内事件就绪的文件描述符个数

epoll的原理

整体思路

有了使用epoll的宏观认识后,再来详细谈谈工作原理

先来看看上面第一个接口所说的创建epoll模型,这个epoll模型到底是什么

以下代码来自linux-2.6.18的源码(使用vscode打开源码根目录可以搜索到下面的代码)

/** This structure is stored inside the "private_data" member of the file* structure and rapresent the main data sructure for the eventpoll* interface.*/
struct eventpoll {/* Protect the this structure access */rwlock_t lock;/** This semaphore is used to ensure that files are not removed* while epoll is using them. This is read-held during the event* collection loop and it is write-held during the file cleanup* path, the epoll file exit code and the ctl operations.*/struct rw_semaphore sem;/* Wait queue used by sys_epoll_wait() */wait_queue_head_t wq;/* Wait queue used by file->poll() */wait_queue_head_t poll_wait;/* List of ready file descriptors */struct list_head rdllist;/* RB-Tree root used to store monitored fd structs */struct rb_root rbr;
};

eventpoll结构体就是epoll模型,重点来看rdllist和rbr两个字段,rbr是一颗红黑树,节点存放了文件描述符和事件的映射关系,里面存放的都是用户传入的的文件描述符,而如果某个文件描述符上的事件就绪了,就会将这个节点插入到rdllist中

rdllist是就绪队列,里面的节点都是已经就绪的文件描述符和对应的事件

所以用户使用epoll_ctl实际就是对这颗红黑树进行增删查改,而一旦有文件描述符就绪了,就会被加入rdllist中,epoll_wait实际上就会得到rdllist中存放的就绪文件描述符的信息。

下面是节点的结构体,可以看到有所属的红黑树的节点的信息,所属的等待队列的节点的信息

实际上,前文所说插入到rdllist并不是复制一个节点插入到rdllist里,而是修改这个节点的rdllink字段,让这个节点属于红黑树的同时,还属于等待队列

struct epitem {/* RB-Tree node used to link this structure to the eventpoll rb-tree */struct rb_node rbn;/* List header used to link this structure to the eventpoll ready list */struct list_head rdllink;/* The file descriptor information this item refers to */struct epoll_filefd ffd;/* Number of active wait queue attached to poll operations */int nwait;/* List containing poll wait queues */struct list_head pwqlist;/* The "container" of this item */struct eventpoll *ep;/* The structure that describe the interested events and the source fd */struct epoll_event event;/** Used to keep track of the usage count of the structure. This avoids* that the structure will desappear from underneath our processing.*/atomic_t usecnt;/* List header used to link this item to the "struct file" items list */struct list_head fllink;/* List header used to link the item to the transfer list */struct list_head txlink;/** This is used during the collection/transfer of events to userspace* to pin items empty events set.*/unsigned int revents;
};

如何判断事件是否就绪

接下来再谈谈epoll如何知道某个文件描述符的事件是否就绪

要解决这个问题,先从下面这个结构体开始

struct file {.../* needed for tty driver, and maybe others */void			*private_data;#ifdef CONFIG_EPOLL/* Used by fs/eventpoll.c to link all the hooks to this file */struct list_head	f_ep_links;spinlock_t		f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */struct address_space	*f_mapping;
};

重点关注这个private_data

当我们创建tcp或者udp套接字时,返回的实际上是文件描述符,内核通过这个文件描述符找到了对应的struct file结构,而这个结构的private_data字段就会指向套接字

struct socket {socket_state		state;unsigned long		flags;const struct proto_ops	*ops;struct fasync_struct	*fasync_list;struct file		*file;struct sock		*sk;wait_queue_head_t	wait;short			type;
};

可以看到socket中还有一个字段是file,这个file就是socket所属的那个struct file的地址

socket下还有sock结构体

struct sock {/** Now struct inet_timewait_sock also uses sock_common, so please just* don't add nothing before this first member (__sk_common) --acme*/...struct sk_buff_head	sk_receive_queue;struct sk_buff_head	sk_write_queue;struct sk_buff_head	sk_async_wait_queue;...
};

太长了省略了一些字段,sock中实际上是各种网络信息,这里最重要的两个就是接收队列和写队列,实际上就是接收缓冲区和发送缓冲区,至此,只需要判断接收缓冲区是否为空就能判断读事件是否就绪

之前说struct file的private_data字段指向struct socket其实还不够准确

我们在创建套接字时常常会指定创建tcp套接字或者udp套接字,private_data会指向这样的struct tcp_socket或者struct udp_socket,而这两个struct结构体实际上会间接包含strcut sock结构

struct tcp_sock {/* inet_connection_sock has to be the first member of tcp_sock */struct inet_connection_sock	inet_conn;...
};
struct inet_connection_sock {/* inet_sock has to be the first member! */struct inet_sock	  icsk_inet;...
};
struct inet_sock {/* sk and pinet6 has to be the first two members of inet_sock */struct sock		sk;...
};
struct udp_sock {/* inet_sock has to be the first member */struct inet_sock inet;...
};
struct inet_sock {/* sk and pinet6 has to be the first two members of inet_sock */struct sock		sk;...
};

可以看到tcp比udp多套了一个管理连接的结构体 struct inet_connection_sock,这里所展现的tcp_sock和udp_sock是一种继承体系,其中strcut sock可看成是基类,剩下的都是子类

而前面的struct socket结构体中的struct sock字段也可能并不是指向一个struct sock的对象,而是指向一个tcp_sock或者udp_sock对象,在需要用到对应tcp或者udp的方法时进行类型强转

这实际上也有一种多态的思想

事件就绪后如何实现将节点插入就绪队列

内核底层提供了一种回调机制,用于处理事件就绪时进行什么动作,默认这个回调是为空的,在epoll这里,这个回调被设置为当事件就绪后把节点插入就绪队列,于是,可以自动的在事件就绪时将节点插入就绪队列。

epoll的优点

使用方便: 虽然拆分成了三个函数, 但是反而使用起来更方便高效. 不需要每次循环都设置关注的文件描述符, 也做到了输入输出参数分离开


数据拷贝轻量: 只在合适的时候调用 EPOLL_CTL_ADD 将文件描述符结构拷贝到内核中, 这个操作并不频繁(而 select/poll 都是每次循环都要进行拷贝)

事件回调机制: 避免使用遍历, 而是使用回调函数的方式, 将就绪的文件描述符结构加入到就绪队列中, epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪. 这个操作时间复杂度 O(1). 即使文件描述符数目很多, 效率也不会受到影响.

没有数量限制: 文件描述符数目无上限.

http://www.dtcms.com/a/436718.html

相关文章:

  • 010网站建设wordpress安全监测
  • 手机网站 制作教程网站界面排版好看
  • 建设网站需要学什么wordpress分类目录插件
  • 网站建设数据处理宁远网站建设
  • 公司网站设计与制商城类网站主要分为哪些模块
  • 友山建站优化wordpress wp_video_shortcode
  • 个人网站建设第一步网站常见的风格
  • 使用vue做的商城网站seo承诺排名的公司
  • 济南定机票网站建设广东建设协会网站
  • 网站200m虚拟主机能放多少东西贵州省交通建设工程质量监督局网站
  • 建立微网站深圳住房和建设局网站哪里预约
  • 网站设计代码在青海省住房和城乡建设厅网站
  • 查询网站最新域名wordpress旅游社区
  • 怎样做网站域名300元建站
  • 为什么要进行网站备案正规网站建设官网
  • ssc网站建设担保交易2018江苏省海门市建设局网站
  • 做竞价的网站需要做外部链接吗最后的目的是什么
  • 佛山市外贸网站建设价格电脑搭建网站
  • 精品课程网站设计与实现开题报告wordpress创建标签页
  • 如何做免费域名网站制作微信公众号的步骤
  • 个人网站怎么建立要多少钱世界工厂采购网登录
  • 智能建站吧贵阳装饰装修公司网站
  • 怎么用手机制作网站福建外贸网站建设
  • 成都专业的网站建设制作公司哪家好廊坊网站关键词排名
  • 做网站还要数据库吗产品网络推广怎样做
  • 响应式网站建设有哪些好处免费优化网站建设
  • 湖北省利川市建设局网站郑青松找谁做的网站
  • 网站性能优化方案网上推广哪家好
  • 做类似淘宝网站怎么做网站前端工资
  • 宁波网站排名提升科技大盗