对于Epoll编程基本模型的理解

本文介绍了一个基于epoll的网络编程模型,并详细解释了epoll_create、epoll_ctl及epoll_wait三个核心函数的工作原理。文章还探讨了如何利用epoll处理客户端连接请求以及数据读取等事件。

 

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; 因此需要将已发生的事件与关注的事件进行比较。


 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值