1

为了了解更多关于 linux 中的 epoll 通知功能,我一直在使用 http 服务器。服务器的结构基本上是有一个表示请求的事件结构数组,然后在一些嵌套的 for 和 while 循环中对其进行迭代。

当我第一次编写这个原始事件循环时,它运行得相当好。但是,当我重构代码时,循环变得不那么可靠了。特别是,我开始收到一堆(大约 75% 的请求)epoll_ctl 错误,其中 errno 被设置为 BADFD。epoll_ctl 显然认为我的套接字文件描述符并不是真正的套接字文件描述符。

然而,我真的很困惑为什么性能会如此下降,因为重构只包括 a) 清理请求的解析和 b) 将 main 函数移到程序的开头。我检查了服务器的先前提交,并将主要功能与新版本进行了比较——它是相同的。

有没有人对这里可能发生的事情有所了解?将不胜感激。

下面是main函数的代码供参考:

int main(int argc, char *argv[]) {
    c("in main");
    char *progname=argv[0];
    int sockfd, newsockfd, portno, clilen, n, pid, epollfd;
    struct sockaddr_in serv_addr, cli_addr;

    initFt();
    if (argc < 2 ) {
        fprintf(stderr, "\nERROR: No Port Provided\n");
        exit(EXIT_FAILURE);
    }
    if (!createSocket(&sockfd)) {
        fprintf(stderr, "%s ERROR, COULD NOT CREATE SERVER SOCKET\n", progname);
        exit(EXIT_FAILURE);
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(atoi(argv[1]));
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    Bind(&sockfd, &serv_addr);
    listen(sockfd, 5);

    struct epoll_event *events = calloc(SOMAXCONN,  sizeof(struct epoll_event));
    struct epoll_event event;
    makeSocketNB(&sockfd);
    event.events = EPOLLIN | EPOLLET;
    event.data.fd = sockfd;

    if ((epollfd = createpoll())<0) {
        fprintf(stderr, "epoll create error\n");
        exit(EXIT_FAILURE);
    }
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &event) == -1) {
        fprintf(stderr, "error with epoll_ctl on sockfd");
        exit(EXIT_FAILURE);
    }

    while (1) {
        int n, e; //e for events
        e = epoll_wait(epollfd, events, SOMAXCONN, -1);

        for (n=0; n<e; n++) {
            if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP) || !(events[n].events & EPOLLIN)) {
                fprintf (stderr, "epoll error\n");
                close (events[n].data.fd);
                continue;
            }
            else if (events[n].data.fd == sockfd) {
                while (1) {
                    newsockfd=accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
                    if (newsockfd>0) {
                        makeSocketNB(&newsockfd);
                        fprintf(stderr, "Accepted a new connection on fd %d, made nonblocking\n", newsockfd);
                    }
                    else if (errno == EAGAIN || errno == EWOULDBLOCK) {
                        fprintf (stderr, "we have accepted all the clients on this event\n");
                        break;
                    }
                    event.data.fd = newsockfd;
                    event.events = EPOLLIN | EPOLLET;
                    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, newsockfd, &event)<0) {
                        fprintf(stderr, "epoll_ctl error\n");
                        if (errno == EEXIST) {
                            fprintf(stderr, "fd already registered\n");
                        }
                        else if (errno == EBADF) {
                            fprintf(stderr, "fd bad\n%d\n", newsockfd);
                            break;
                        }
                        else if (errno == ENOMEM) {
                            fprintf(stderr, "no memory\n");
                        }
                        else if (errno == ENOSPC) {
                            fprintf(stderr, "enospc\n");
                        }
                        exit(EXIT_FAILURE);
                    }
                    continue;
                }
            }
            else { // there is stuff for us to read
                handleResponse(&events[n].data.fd);
                fprintf(stderr, "we are about to close file descriptor %d\n", events[n].data.fd);
                close (events[n].data.fd);
                fprintf(stderr, "connection closed\n");
            }
        }
    }

    exit(EXIT_SUCCESS);
}
4

1 回答 1

2

您的accept代码并没有真正处理错误:它只处理“成功”情况和将阻止情况。

if (newsockfd>0) {
    /* success */
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
    /* wouldblock */
}

/* Could be error but you call `epoll_ctl` anyway. */
于 2012-05-11T06:37:42.797 回答