zoukankan      html  css  js  c++  java
  • epoll使用总结

    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

  • 相关阅读:
    mysql事务
    python zip dict函数
    有关mysql索引
    hash(散列函数)
    Docker使用
    Mac终端命令自动补全
    python序列化与反序列化(json与pickle)
    python txt、excel读写
    python 正则表达式
    python进行数据预处理-pandas
  • 原文地址:https://www.cnblogs.com/bugchecker/p/tips_of_using_epoll.html
Copyright © 2011-2022 走看看