epoll使用总结

非 Y 不嫁゛ 提交于 2019-11-28 09:02:22

epoll的使用总结

使用epoll来实现一个tcp server,中间碰到了不少使用细节上的问题,总结一下。

 

man epoll里推荐的使用方法

epoll使用代码
           #define MAX_EVENTS 10
           struct epoll_event ev, events[MAX_EVENTS];
           int listen_sock, conn_sock, nfds, epollfd;

           /* Set up listening socket, 'listen_sock' (socket(),
              bind(), listen()) */

           epollfd = epoll_create(10);
           if (epollfd == -1) {
               perror("epoll_create");
               exit(EXIT_FAILURE);
           }

           ev.events = EPOLLIN; // 不要写成ev.events = EPOLLIN | EPOLLET;
           ev.data.fd = listen_sock;
           if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
               perror("epoll_ctl: listen_sock");
               exit(EXIT_FAILURE);
           }

           for (;;) {
               nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
               if (nfds == -1) {
                   perror("epoll_pwait");
                   exit(EXIT_FAILURE);
               }

               for (n = 0; n < nfds; ++n) {
                   if (events[n].data.fd == listen_sock) {
                       conn_sock = accept(listen_sock,
                                       (struct sockaddr *) &local, &addrlen);
                       if (conn_sock == -1) {
                           perror("accept");
                           exit(EXIT_FAILURE);
                       }
                       setnonblocking(conn_sock);
                       ev.events = EPOLLIN | EPOLLET;
                       ev.data.fd = conn_sock;
                       if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
                                   &ev) == -1) {
                           perror("epoll_ctl: conn_sock");
                           exit(EXIT_FAILURE);
                       }
                   } else {
                       do_use_fd(events[n].data.fd);
                   }
               }
           }

 

要点:
1.listen_sock使用LT模式,其他使用ET模式,这样就不会遗漏后续的connect请求
(其实还有另外一种方式,listen_sock也使用ET模式,只是要用while包裹accept语句,直到返回-1,这里我们不讨论)

 

在遗落后续的connect请求这个问题上花费了很多时间。
具体测试表现是:1000个client发起tcp connect,并在连接成功之后发送数据。测试中,1000个client正常连接并发送数据,但epoll中未收到部分client的连接请求。
使用netstat命令查看有以下发现:

netstat -apn|grep 7777|wc -l
1001
netstat -apn|grep 7777|grep -|wc -l
139

系统已经建立了1000个tcp连接,但是其中有小部分连接不是由我们的程序负责建立的。

netstat -apn|grep 7777|grep -

使用上面的命令能够发现,有小部分连接处于ESTABLISHED状态,但进程信息那一栏却是"-"

这应该是ET模式下连接就绪触发了一次,但我们的程序没有来及处理,ET不会再触发,导致这小部分连接再没有机会得到accept处理。
解决这个问题的话,把listen_sock(负责listen和accept新连接的socket)设成LT模式,这样没来得及处理的connect请求会在下次执行到epoll_wait时继续得到处理。

2.epoll_wait的参数设置
#include <sys/epoll.h>

int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
maxevents参数越小,相同请求数的情况下,需要调用更多次数的epoll_wait来处理这些在epoll队列里的请求,可能会有效率损失。
timeout参数:一般设置成-1,即没有请求时无限等待。


参考资料:
1.http://stackoverflow.com/questions/6401642/dealing-with-listening-socket-by-epoll
2.http://stackoverflow.com/questions/9577230/epoll-create-and-epoll-wait
3.http://stackoverflow.com/questions/16640430/maxevents-parameter-in-epoll-wait-and-the-events-array-size

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!