Linux Epool 使用学习笔记

来源:互联网 发布:渲染软件哪个好 编辑:程序博客网 时间:2024/05/19 00:38

头文件

#include <sys/epool.h>

接口和结构体

/* Creates an epoll instance.  Returns an fd for the new instance.   The "size" parameter is a hint specifying the number of file   descriptors to be associated with the new instance.  The fd   returned by epoll_create() should be closed with close().  *//*创建一个epool实例。为这个实例返回一个文件描述符。size参数是这个实例所关联的文件描述符个数。返回的文件描述符应该被close接口关闭。*/extern int epoll_create (int __size) __THROW;/* Same as epoll_create but with an FLAGS parameter.  The unused SIZE   parameter has been dropped.  *//*和epool_create一样但是带着FLAGS参数。遗弃了size参数。*/extern int epoll_create1 (int __flags) __THROW;/* Valid opcodes ( "op" parameter ) to issue to epoll_ctl().  */#define EPOLL_CTL_ADD 1 /* Add a file descriptor to the interface.  */#define EPOLL_CTL_DEL 2 /* Remove a file descriptor from the interface.  */#define EPOLL_CTL_MOD 3 /* Change file descriptor epoll_event structure.  *//* Manipulate an epoll instance "epfd". Returns 0 in case of success,   -1 in case of error ( the "errno" variable will contain the   specific error code ) The "op" parameter is one of the EPOLL_CTL_*   constants defined above. The "fd" parameter is the target of the   operation. The "event" parameter describes which events the caller   is interested in and any associated user data.  *//*管理epfd代表的epool实例。如果成功返回0, 出错返回-1(出错码写入errno)。op参数是上面定义的EPOLL_CTL_*中的一个。event参数包含调用者关心的的事件和对应的数据(触发类型,fd)*/extern int epoll_ctl (int __epfd, int __op, int __fd,              struct epoll_event *__event) __THROW;/* Wait for events on an epoll instance "epfd". Returns the number of   triggered events returned in "events" buffer. Or -1 in case of   error with the "errno" variable set to the specific error code. The   "events" parameter is a buffer that will contain triggered   events. The "maxevents" is the maximum number of events to be   returned ( usually size of "events" ). The "timeout" parameter   specifies the maximum wait time in milliseconds (-1 == infinite).   This function is a cancellation point and therefore not marked with   __THROW.  *//*等待发生在epfd表示的epool实例上的事件。返回值是在events参数中返回的event缓存的大小。0或者-1代表出错,出错码保存在errno中。events参数指向包含触发数据的缓存。maxevents表示返回缓存的最大数目。timeout参数指定最大等待时间(-1表示永久)。*/extern int epoll_wait (int __epfd, struct epoll_event *__events,               int __maxevents, int __timeout);

EPOLL_EVENTS

enum EPOLL_EVENTS  {    EPOLLIN = 0x001,#define EPOLLIN EPOLLIN         EPOLLPRI = 0x002,#define EPOLLPRI EPOLLPRI    EPOLLOUT = 0x004,#define EPOLLOUT EPOLLOUT    EPOLLRDNORM = 0x040,#define EPOLLRDNORM EPOLLRDNORM    EPOLLRDBAND = 0x080,#define EPOLLRDBAND EPOLLRDBAND    EPOLLWRNORM = 0x100,#define EPOLLWRNORM EPOLLWRNORM    EPOLLWRBAND = 0x200,#define EPOLLWRBAND EPOLLWRBAND    EPOLLMSG = 0x400,#define EPOLLMSG EPOLLMSG    EPOLLERR = 0x008,#define EPOLLERR EPOLLERR    EPOLLHUP = 0x010,#define EPOLLHUP EPOLLHUP    EPOLLRDHUP = 0x2000,#define EPOLLRDHUP EPOLLRDHUP    EPOLLWAKEUP = 1u << 29,#define EPOLLWAKEUP EPOLLWAKEUP    EPOLLONESHOT = 1u << 30,#define EPOLLONESHOT EPOLLONESHOT    EPOLLET = 1u << 31#define EPOLLET EPOLLET  };

epoll_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 */} ;

实例代码

来自 :

http://blog.csdn.net/xiajun07061225/article/details/9250579

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <sys/socket.h>#include <netdb.h>#include <fcntl.h>#include <sys/epoll.h>#include <string.h>#define MAXEVENTS 64//函数://功能:创建和绑定一个TCP socket//参数:端口//返回值:创建的socket    static intcreate_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;     /* Return IPv4 and IPv6 choices */    hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */    hints.ai_flags = AI_PASSIVE;     /* All interfaces */    s = getaddrinfo (NULL, port, &hints, &result);    if (s != 0)    {        fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (s));        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)        {            /* We managed to bind successfully! */            break;        }        close (sfd);    }    if (rp == NULL)    {        fprintf (stderr, "Could not bind\n");        return -1;    }    freeaddrinfo (result);    return sfd;}//函数//功能:设置socket为非阻塞的    static intmake_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;}//端口由参数argv[1]指定    intmain (int argc, char *argv[]){    int sfd, s;    int efd;    struct epoll_event event;    struct epoll_event *events;    if (argc != 2)    {        fprintf (stderr, "Usage: %s [port]\n", argv[0]);        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, SOMAXCONN);    if (s == -1)    {        perror ("listen");        abort ();    }    //除了参数size被忽略外,此函数和epoll_create完全相同    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 ();    }    /* Buffer where events are returned */    events = calloc (MAXEVENTS, sizeof event);    /* The event loop */    while (1)    {        int n, i;        n = epoll_wait (efd, events, MAXEVENTS, -1);        for (i = 0; i < n; i++)        {            if ((events[i].events & EPOLLERR) ||                    (events[i].events & EPOLLHUP) ||                    (!(events[i].events & EPOLLIN)))            {                /* An error has occured on this fd, or the socket is not                   ready for reading (why were we notified then?) */                fprintf (stderr, "epoll error\n");                close (events[i].data.fd);                continue;            }            else if (sfd == events[i].data.fd)            {                /* We have a notification on the listening socket, which                   means one or more incoming connections. */                while (1)                {                    struct sockaddr in_addr;                    socklen_t in_len;                    int infd;                    char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];                    in_len = sizeof in_addr;                    infd = accept (sfd, &in_addr, &in_len);                    if (infd == -1)                    {                        if ((errno == EAGAIN) ||                                (errno == EWOULDBLOCK))                        {                            /* We have processed all incoming                               connections. */                            break;                        }                        else                        {                            perror ("accept");                            break;                        }                    }                    //将地址转化为主机名或者服务名                    s = getnameinfo (&in_addr, in_len,                            hbuf, sizeof hbuf,                            sbuf, sizeof sbuf,                            NI_NUMERICHOST | NI_NUMERICSERV);//flag参数:以数字名返回                    //主机地址和服务地址                    if (s == 0)                    {                        printf("Accepted connection on descriptor %d "                                "(host=%s, port=%s)\n", infd, hbuf, sbuf);                    }                    /* Make the incoming socket non-blocking and add it to the                       list of fds to monitor. */                    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            {                /* We have data on the fd waiting to be read. Read and                   display it. We must read whatever data is available                   completely, as we are running in edge-triggered mode                   and won't get a notification again for the same                   data. */                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, that means we have read all                           data. So go back to the main loop. */                        if (errno != EAGAIN)                        {                            perror ("read");                            done = 1;                        }                        break;                    }                    else if (count == 0)                    {                        /* End of file. The remote has closed the                           connection. */                        done = 1;                        break;                    }                    /* Write the buffer to standard output */                    s = write (1, buf, count);                    if (s == -1)                    {                        perror ("write");                        abort ();                    }                }                if (done)                {                    printf ("Closed connection on descriptor %d\n",                            events[i].data.fd);                    /* Closing the descriptor will make epoll remove it                       from the set of descriptors which are monitored. */                    close (events[i].data.fd);                }            }        }    }    free (events);    close (sfd);    return EXIT_SUCCESS;}

运行方式:
在一个终端运行此程序:a.out PORT
另一个终端:telnet 127.0.0.1 PORT

1 0
原创粉丝点击