epollfd = epoll_create(...) //创建epoll描述符
listenfd = socket(...) //创建用于端口监听的socket
bind(listenfd ...) //绑定
listen(listenfd ...) //开始在端口监听
epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd...) //将listenfd加入epoll描述符监听
for(;;) //无限循环
{
n = epoll_wait(...) //等待epoll描述符的事件发生
for(0 ~ n) //遍历发生的所有事件
{
if(events[i].data.fd == listenfd) //通过发生事件的socket描述符确认有新链接,
{ //而非已经打开的socket的读写事件
connfd = accpet(...) //accept新连接为connfd
epoll_ctl(...) //connfd加入epoll监听,像上面listenfd一样
}
else if(events[i].events & EPOLLIN) //发生事件的socket不是listenfd而是connfd
{ //且事件集里有EPOLLIN表明有数据要读取
n = read(...) //读取数据
if(n == 0) //读到0字节,需要关闭socket
close(connfd) //close会自动将connfd从epoll监听中删除
} //无需调用epoll_ctl(..EPOLL_CTL_DEL..)
else if(...) //其他各种事件处理依次处理
... }
}
以上是epoll编程基本模型的伪代码。下面对epoll的三大函数进行简要说明。
(1) int epoll_create(int size);
epoll_create()用于创建一个epoll的事例/句柄,它通知内核需要监听size个fd。当创建成功后,会占用一个fd,因此必须及时调用close()函数以免fd被耗尽。
epoll_create()对应的内核函数为sys_epoll_create,这个函数做一些准备工作,创建数据结构,初始化数据并最终返回一个fd(表示新创建的虚拟epoll文件)。
(2) int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
select()函数用于在监听时告诉内核要监听的事件,而epoll_etl()函数用于先注册要监听的事件。其中,fd表示要监听的fd,event表示需要监听的事件。
epoll_ctl()对应的内核函数为sys_epoll_ctl,每次调用sys_epoll_ctl只处理一个fd。当op为EPOLL_CTL_ADD时,sys_epoll_ctl先做一些安全检查,然后进入ep_insert。在ep_insert里将ep_poll_callback作为回调函数加入设备的等待队列(假定此时设备尚未就绪)。ep_poll_callback这个函数在所等待的设备就绪后被系统回调,执行两个操作:其一,将就绪设备加入到就绪队列;其二,唤醒虚拟的epoll文件,即用epoll_create创建的fd。
(3) int epoll_wait(int epfd, struct epoll_event*events, int maxevents, int timeout);
man一下可知,它是等待发生在一个epoll文件描述符上的IO事件的函数。events指针指向的内存包含对调用者有效的事件。
epoll_wait()对应的内核函数为sys_epoll_wait,实际执行操作的是ep_poll函数。该函数将进程自己插入虚拟epoll文件的等待队列,直到被唤醒。最后执行ep_events_transfer将结果拷贝到用户空间。
对于events[i].data.fd == listenfd的理解:我的理解是,已发生的事件必然是由客户端引起的,客户端试图连接listenfd所在端口,因此events的fd等于了listenfd。或者这样来分析:当socket函数创建一个套接字是,它被假设为主动套接字,即是一个将调用connect函数发起连接的客户套接字。listen函数把一个未连接的套接字转换为一个被动套接字,指示内核应接受指向该套接字的连接请求,即监听某个端口。更进一步地,注意到注册要关注的事件时有这么一句ev.data.fd = listenfd; 因此需要将已发生的事件与关注的事件进行比较。
本文介绍了一个基于epoll的网络编程模型,并详细解释了epoll_create、epoll_ctl及epoll_wait三个核心函数的工作原理。文章还探讨了如何利用epoll处理客户端连接请求以及数据读取等事件。
782

被折叠的 条评论
为什么被折叠?



