zoukankan      html  css  js  c++  java
  • epoll

    epoll相关的api:

    /* 创建一个epoll实例。返回一个实例的fd。"size"参数是该epoll实例关联
       文件描述符数量的暗示。epoll_create()返回的fd应该用close()关闭。 */
    extern int epoll_create (int __size) __THROW;
    
    /* 把"fd"文件描述符,注册到"epfd" epoll实例。
       "op"参数是EPOLL_CTL_*常量,"event"参数描述调用者感兴趣的事件。 */
    extern int epoll_ctl (int __epfd, int __op, int __fd,
                  struct epoll_event *__event) __THROW;
    
    //每次调用epoll_wait,发生了事件的描述符会保存在events数组中。
    /* 等待"epfd" epoll实例上的事件。返回值是"events"数组中触发事件的数量
       "events"参数是包含触发事件的数组。"maxevents"是返回的最大的触发事件
       的个数,通常是"events"的大小。"timeout"是等待的最大时间,-1表示无限。 */
    extern int epoll_wait (int __epfd, struct epoll_event *__events,
                   int __maxevents, int __timeout);
    
                   
    /* Valid opcodes ( "op" parameter ) to issue to epoll_ctl().  */
    #define EPOLL_CTL_ADD 1    
    #define EPOLL_CTL_DEL 2    
    #define EPOLL_CTL_MOD 3    
                   
    struct epoll_event
    {
      uint32_t events;    /* Epoll events */
      epoll_data_t data;    /* User data variable */
    } __EPOLL_PACKED;
    
    typedef union epoll_data
    {
      void *ptr;
      int fd;
      uint32_t u32;
      uint64_t u64;
    } epoll_data_t;

    网上搜集的epoll代码示例:

    #include <stdio.h>
    #include <stdlib.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <sys/epoll.h>
    #include <errno.h>
    #include <netdb.h>
    #include <fcntl.h>
    #include <string.h>
    
    #define MAXEVENTS 64
    
    static int create_and_bind(char*);
    static int make_socket_non_blocking(int);
    
    int main(int argc, char *argv[]) {
        int listenfd, s;
        int efd;
        struct epoll_event event;
        struct epoll_event *events;
    
        if (argc != 2) {
            fprintf(stderr, "Usage: %s [port]
    ", argv[0]);
            exit(EXIT_FAILURE);
        }
    
        listenfd = create_and_bind(argv[1]);
        if (listenfd == -1)
            abort();
    
        s = make_socket_non_blocking(listenfd);
        if (s == -1)
            abort();
    
        s = listen(listenfd, SOMAXCONN);
        if (s == -1) {
            perror("listen");
            abort();
        }
    
        //首先得到一个epoll实例标识符
        efd = epoll_create1(0);
        if (efd == -1) {
            perror("epoll_create");
            abort();
        }
    
        event.data.fd = listenfd;
        event.events = EPOLLIN | EPOLLET;
        //listenfd和&event是一对,表示我们所关心的套接字的事件,并注册到epoll实例
        s = epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &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
    ");
                    close(events[i].data.fd);
                    continue;
                } else if (listenfd == events[i].data.fd) {
                    /* We have a notification on the listening socket, which
                     means one or more incoming connections. */
                    while (1) {
                        struct sockaddr clientaddr;
                        socklen_t addrlen;
                        int connfd;
                        char hostbuf[NI_MAXHOST], portbuf[NI_MAXSERV];
    
                        addrlen = sizeof clientaddr;
                        connfd = accept(listenfd, &clientaddr, &addrlen);
                        if (connfd == -1) {
                            if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                                /* We have processed all incoming
                                 connections. */
                                break;
                            } else {
                                perror("accept");
                                break;
                            }
                        }
    
                        s = getnameinfo(&clientaddr, addrlen, hostbuf, sizeof hostbuf, portbuf, sizeof portbuf,
                                NI_NUMERICHOST | NI_NUMERICSERV);
                        if (s == 0) {
                            printf("Accepted connection on descriptor %d "
                                    "(host=%s, port=%s)
    ", connfd, hostbuf, portbuf);
                        }
    
                        /* Make the incoming socket non-blocking and add it to the
                         list of fds to monitor. */
                        s = make_socket_non_blocking(connfd);
                        if (s == -1)
                            abort();
    
                        //新产生的套接字,仍然需要注册到epoll实例
                        event.data.fd = connfd;
                        event.events = EPOLLIN | EPOLLET;
                        s = epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &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
    ",
                                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(listenfd);
    
        return EXIT_SUCCESS;
    }
    
    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; /* 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
    ", 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
    ");
            return -1;
        }
        freeaddrinfo(result);
        return sfd;
    }
    
    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;
    }
  • 相关阅读:
    week4:周测错题
    小程序1:登录/注册小程序
    小程序2:实现一个购物车
    day26:装饰器&面向对象当中的方法&property
    day25:7个魔术方法&5个关于类的魔术属性
    day24:多态&魔术方法__new__&单态模式
    day23:单继承&多继承&菱形继承&__init__魔术方法
    day22:面向对象封装对象操作&类操作&面向对象删除操作
    day21:正则函数&模块和包(import)
    APP探索之iAPP
  • 原文地址:https://www.cnblogs.com/allenwas3/p/7977220.html
Copyright © 2011-2022 走看看