epoll 学习笔记

来源:互联网 发布:bandcamp 知乎 编辑:程序博客网 时间:2024/05/16 11:37

1 Epoll函数

首先看一下epoll的几个函数的介绍。

1.1 epoll_create函数

1.1.1 函数原型

/**  * @brief   该函数生成一个epoll专用的文件描述符。它其实是在内核申请一空间,用来存放你想关注的socket fd上是否发生以及发生了什么事件。 *  * @param   size    size就是你在这个epoll fd上能关注的最大socketfd数 *  * @return  生成的文件描述符 */int epoll_create(int size);

1.1.2 函数实例

/* listener为socket文件描述符,kdpfd为epoll文件描述符 */int listener, kdpfd;    struct sockaddr_in my_addr;/* 创建socket */    if ((listener =socket(PF_INET, SOCK_STREAM, 0)) == -1)    {        perror("socket");        exit(1);    }   bzero(&my_addr,sizeof(my_addr));    my_addr.sin_family = PF_INET;    my_addr.sin_port = htons(PORT);my_addr.sin_addr.s_addr =INADDR_ANY;/* 绑定socket */    if (bind(listener, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)    {        perror("bind");        exit(1);    }    /*监听socket */    if (listen(listener, LISNUM)== -1)    {        perror("listen");        exit(1);    }/* 以上初始化完成后,创建epoll 句柄,也可以先创建epoll句柄,再初始化socket */    kdpfd =epoll_create(MAXEPOLLSIZE);

1.2 epoll_ctl函数

1.2.1 函数原型

/**  * @brief   该函数用于控制某个epoll文件描述符上的事件,可以注册事件,修改事件,删除事件。 *  * @param   epfd    由 epoll_create 生成的epoll专用的文件描述符 * @param   op      要进行的操作例如注册事件,可能的取值EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修 改、EPOLL_CTL_DEL 删除 * @param   fd      关联的文件描述符 * @param   event   指向epoll_event的指针 *  * @return  0       succ *          -1      fail */int epoll_ctl(int epfd,int op,int fd,structepoll_event*event);

其中用到的数据结构结构如下:

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

常用的事件类型:

EPOLLIN :表示对应的文件描述符可以读;

EPOLLOUT:表示对应的文件描述符可以写;

EPOLLPRI:表示对应的文件描述符有紧急的数据可读

EPOLLERR:表示对应的文件描述符发生错误;

EPOLLHUP:表示对应的文件描述符被挂断;

EPOLLET: 表示对应的文件描述符有事件发生;

1.2.2 函数实例

    struct epoll_event ev;    //设置要处理的事件类型    ev.events =EPOLLIN | EPOLLET;    //设置与要处理的事件相关的文件描述符    ev.data.fd =listener;    //注册epoll事件,将监听的socket加入epoll    if (epoll_ctl(kdpfd,EPOLL_CTL_ADD, listener, &ev) < 0)    {        fprintf(stderr,"epoll set insertion error: fd=%d\n", listener);        return -1;    }

1.3 epoll_wait函数

1.3.1 函数原型

/**  * @brief   该函数用于轮询I/O事件的发生 *  * @param   epfd        由epoll_create 生成的epoll专用的文件描述符 * @param   events      用于回传代处理事件的数组 * @param   maxevents   每次能处理的事件数 * @param   timeout     等待I/O事件发生的超时值;-1相当于阻塞,0相当于非阻塞。一般用-1即可 *  * @return  >=0         返回发生事件数 *          -1          错误 */int epoll_wait(int epfd,structepoll_event* events,int maxevents,int timeout);

1.3.2 函数实例

struct epoll_event events[MAXEPOLLSIZE];while (1)    {        /* 等待有事件发生 */        nfds =epoll_wait(kdpfd, events, curfds,-1);        if (nfds == -1)        {            perror("epoll_wait");            break;        }        /* 处理所有事件 */        for (n = 0; n <nfds; ++n)        {            if (events[n].data.fd == listener)            {                new_fd = accept(listener, (struct sockaddr *)&their_addr,&sizeof(struct sockaddr_in));               if (new_fd < 0)               {                   perror("accept");                   continue;               }               else               {                   printf("有连接来自于: %d:%d,分配的 socket为:%d\n",                           inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);               }               setnonblocking(new_fd);               ev.events = EPOLLIN | EPOLLET;               ev.data.fd = new_fd;               if (epoll_ctl(kdpfd,EPOLL_CTL_ADD, new_fd, &ev) < 0)               {                   fprintf(stderr,"把 socket '%d'加入 epoll失败!%s\n",                           new_fd, strerror(errno));                   return -1;                }                curfds++;            }            else            {               ret= handle_message(events[n].data.fd);               if (ret < 1&& errno != 11)               {                   epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,&ev);                   curfds--;               }            }        }    }    close(listener);
原创粉丝点击