epoll的基本使用

epoll:为处理大量文件描述符,而改进的poll;

特点:每个文件描述符及事件是在结构体中,而且是存放在链表中,需要是添加,不需要时释放,不会占用多的空间;

三个系统调用函数:

头文件:#include <sys/epoll.h>

int epoll_create(int size);

功能:

创建epoll

参数:

int size:目前已经失效

返回值:

失败:-1,set errno

成功:文件描述符

所以epoll创建成功后,也会占用一个文件描述符,需要释放close(fd),否则会导致fd耗尽;

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

功能:

epoll的事件注册函数,不同于select()是在监听事件时告诉内核要监听什么类型的事件,而是先要 在这里注册要监听的事件类型;注册、删除、修改epoll链表中的指定节点;

参数:

int epfd:epoll的文件描述符,创建函数的返回值

int op:命令码

EPOLL_CTL_ADD 注册一个监测对象

EPOLL_CTL_MOD 修改一个监测对象

EPOLL_CTL_DEL 删除一个监测对象

int fd:需要监听的对象(文件描述符)

struct epoll_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*/

}

其中events是以下一个或几个宏的集合

EPOLLIN:表示对应文件描述符可以读(包括对端SOCKET正常关闭)

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

EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示带外数据到来)

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

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

EPOLLET:将EPOLL设为边缘事件(多次触发,直到把数据读完为止)

EPOLLONESHOT:只监听一次事件,如果要监听需要把fd重新加入到epoll中;

返回值:

失败:-1,错误码在errno中

成功:文件描述符

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

功能:

等结果

参数:

int epfd:epoll的文件描述符

struct epoll_event *events:用于保存结构的事件数组(events不能是空指针)

int maxevents:告诉内核这个数组有多大

int timeout:超时时间

返回值:

-1:调用失败

0:超时

成功:返回实际发生的事件的数量

epoll的工作原理:返回实际发生事件文件描述符的数量,可以帮助你从数组中有效的找到什 么事件发生,而不用遍历整个数组,这里数组使用了mmap技术,不用再一次复制粘贴;

示例代码:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>        
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/epoll.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define PORT 17000
#define MAX 1023

int set_fcntl(int rws)
{
    int flags = fcntl(rws,F_GETFD);
    if(flags < 0) {
        perror("get fcntl errnor");
        return -1;
    }
    flags |= O_NONBLOCK;
    if(fcntl(rws,F_SETFD,flags) < 0) {
        perror("set fcntl errnor");
        return -1;
    }
    return 0;
}

 int main()
{
    int sockfd;
    struct sockaddr_in myaddr;
    sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd < 0) {
        perror("creat sockfd failed");
        return -1;
    }
    printf("socket................................................\n");
    int on = 1;
    if (0 > setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) {
        perror("setsockopt");
        return -1;
    }

    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(PORT);
    myaddr.sin_addr.s_addr = INADDR_ANY;

    if(bind(sockfd,(const struct sockaddr *)&myaddr,sizeof(myaddr)) < 0) {
        perror("bind failed");
        return -1;
    }
    printf("bind................................................\n");
    if(listen(sockfd,10) < 0) {
        perror("listen failed");
        return -1;
    }

    //epoll fd
    int efd = epoll_create(1);
    if(efd < 0) {
        printf("efd errno\n");
        return -1;
    }
    printf("epoll creat.....................................\n");
    
    //put listen_fd to epoll_fd
    struct epoll_event evt = {
        .events = EPOLLIN,
        .data.fd = sockfd,
    };
    if(epoll_ctl(efd,EPOLL_CTL_ADD,sockfd,&evt) < 0){
        printf("put listen_fd epoll errno\n");
        return -1;    
    }
    printf("listen fd add epoll.....................................\n");

    char buf[1024] = {0};
    struct epoll_event events[MAX];
    while(1) {
        int i = 0;
        int num = epoll_wait(efd,events,MAX,~0);
        printf("wait events.....................................\n");
        if(num < 0) {
            printf("epoll_wait events start  errno\n");
            return -1;
        }

        for(i = 0; i < num; i++ ) {
            if(events[i].events & EPOLLIN) {
                if(sockfd == events[i].data.fd) {
                    int cn_fd = accept(sockfd,NULL,NULL);
                    set_fcntl(cn_fd);
                    printf("accept................................................\n");
                    if(cn_fd < 0) {
                        printf("accept fd errnor\n");
                        return -1;
                    }

                    struct epoll_event ac_evt = {
                        .events = EPOLLIN,
                        .data.fd = cn_fd,
                    };
                    if(epoll_ctl(efd,EPOLL_CTL_ADD,cn_fd,&ac_evt) < 0){
                        printf("put accept_fd epoll errno\n");
                        return -1;    
                    }

                }
                else {
                    int len = read(events[i].data.fd,buf,sizeof(buf));
                    if(len <= 0) {
                        struct epoll_event ac_evt1;
                        if(epoll_ctl(efd,EPOLL_CTL_DEL,events[i].data.fd,&ac_evt1) < 0){
                            printf("delete accept_fd epoll errno\n");
                            return -1;    
                        }
                        close(events[i].data.fd);
                    }
                    else {
                        printf("%s\n",buf);
                        write(events[i].data.fd,buf,len);
                    }
                }
            }
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值