epoll 学习笔记

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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值