EPOLL学习笔记

EPOLL学习笔记

    在网络编程的多路复用模型中传统的select只能监视一定数量的套接字,poll没有这个限制,但也必须线性的扫描监视的套接字集中各个套接字的状态,而epoll模型则不存在这个问题。函数返回制定时间内由状态变化的套接字个数N,对应套接字集合中的前N个套接字。epoll分为2种工作模式,
level-triggered模式下,只要有数据没有接受都会随epoll_wait函数返回,edge-triggered模式下则只提示一次,即可能需要多次调用recv函数直到确定没有数据要接受。
   epoll模型主要用到3个函数,epoll_create函数用于创建一个epoll描述符,epoll_ctl函数用于添加移除变更epoll描述符对应的套接字描述符,epoll_wait函数用于等待监控的套接字字符集由事件发生,或者超时返回。以下是一个回显采用epoll模型服务器的例子。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <errno.h>

#define MAX 20000

static int
make_socket_non_blocking(int sfd)
{
    int flags,s;

    flags=fcntl(sfd,F_GETFL,0);
    if(flags==-1)
    {
        perror("fcntl");
        return -1;
    }

    flags|=O_NONBLOCK;
    s=fcntl(sfd,F_SETFL,flags);
    if(s==-1)
    {
        perror("fcntl");
        return -1;
    }

    return 0;
}

static int
create_and_bind(char *port)
{
    struct addrinfo hints;
    struct addrinfo *result,*rp;
    int s,sfd;

    memset(&hints,0,sizeof(struct addrinfo));
    hints.ai_family=AF_UNSPEC;
    hints.ai_socktype=SOCK_STREAM;
    hints.ai_flags=AI_PASSIVE;

    s=getaddrinfo(NULL,port,&hints,&result);
    if(s!=0)
    {
        perror("getaddrinfo");
        return -1;
    }

    for(rp=result;rp!=NULL;rp=rp->ai_next)
    {
        sfd=socket(rp->ai_family,rp->ai_socktype,rp->ai_protocol);
        if(sfd==-1)
        continue;

        s=bind(sfd,rp->ai_addr,rp->ai_addrlen);
        if(s==0)
        break;

        close(sfd);
    }

    if(rp==NULL)
    {
        perror("bind");
        return -1;
    }

    freeaddrinfo(result);
    return sfd;
}

int
main(int argc,char *argv[])
{
    int sfd,s;
    int efd;
    struct epoll_event event;
    struct epoll_event *events;

    if(argc!=2)
    {
        perror("argc");
        exit(EXIT_FAILURE);
    }

    sfd=create_and_bind(argv[1]);
    if(sfd==-1)
    abort();

    s=make_socket_non_blocking(sfd);
    if(s==-1)
    abort();
    
    s=listen(sfd,128);
    if(s==-1)
    {
        perror("listen");
        return -1;
    }

    efd=epoll_create1(0);
    if(efd==-1)
    {
        perror("epoll_create");
        abort();
    }

    event.data.fd=sfd;
    event.events=EPOLLIN|EPOLLET;
    s=epoll_ctl(efd,EPOLL_CTL_ADD,sfd,&event);
    if(s==-1)
    {
        perror("epoll_ctl");
        abort();
    }
    events=calloc(MAX,sizeof(event));

    while(1)
    {
        int n,i;

        n=epoll_wait(efd,events,MAX,-1);
        for(i=0;i<n;++i)
        {
            if((events[i].events&EPOLLERR)||
                (events[i].events&EPOLLHUP)||
                (!(events[i].events&EPOLLIN)))
            {
                perror("epoll error");
                close(events[i].data.fd);
                continue;
            }
            else if(sfd==events[i].data.fd)
            {
                while(1)
                {
                    struct sockaddr in_addr;
                    socklen_t in_len;
                    int infd;
                    char hbuf[1024],sbuf[1024];

                    in_len=sizeof(in_addr);
                    infd=accept(sfd,&in_addr,&in_len);
                    if(infd==-1)
                    {
                        if((errno==EAGAIN)||
                            (errno==EWOULDBLOCK))
                        break;
                        else
                        {
                            perror("accept");
                            break;
                        }    
                    }

                    s=getnameinfo(&in_addr,in_len,hbuf,sizeof(hbuf),
                                    sbuf,sizeof(sbuf),NI_NUMERICSERV|NI_NUMERICHOST);
                    if(s==0)
                    {
                        printf("accepted connection on des %d,host=%s,port=%s\n",infd,hbuf,sbuf);
                    }

                    s=make_socket_non_blocking(infd);
                    if(s==-1)
                    abort();

                    event.data.fd=infd;
                    event.events=EPOLLIN|EPOLLET;
                    s=epoll_ctl(efd,EPOLL_CTL_ADD,infd,&event);
                    if(s==-1)
                    {
                        perror("epoll_ctl");
                        abort();
                    }
                }
                continue;
            }
            else
            {
                int done=0;

                while(1)
                {
                    ssize_t count;
                    char buf[512];
                    count=read(events[i].data.fd,buf,sizeof(buf));
                    if(count==-1)
                    {
                        if(errno!=EAGAIN)
                        {
                            perror("read");
                            done=1;
                        }
                        break;
                    }
                    else if (count==0)
                    {
                        done=1;
                        break;
                    }
                    s=write(1,buf,count);
                    if(s==-1)
                    {
                        perror("write");
                        abort();
                    }
                }
                if(done)
                {
                    printf("close connection on des %d\n",events[i].data.fd);
                    close(events[i].data.fd);
                }
            }

        }
    }

    free(events);
    close(sfd);

    return EXIT_SUCCESS;
}

你可能感兴趣的:(EPOLL学习笔记)