高级I/O复用技术:Epoll的使用及一个完整的C实例

高性能的网络服务器需要同时并发处理大量的客户端,而采用以前的那种对每个连接使用一个分开的线程或进程方法效率不高,因为处理大量客户端的时候,资源的使用及进程上下文的切换将会影响服务器的性能。一个可替代的方法是在一个单一的线程中使用非阻塞的I/O(non-blocking I/O)。

        这篇文章主要介绍linux下的epoll(7)方法,其有着良好的就绪事件通知机制。我们将会使用C来展现一个完整的TCP服务器实现代码。Epoll是被linux2.6开始引进的,但是不被其他的类UNIX系统支持,它提供了一种类似select或poll函数的机制:

   1.Select(2)只能够同时管理FD_SETSIZE数目的文件描述符

       2. poll(2)没有固定的描述符上限这一限制,但是每次必须遍历所有的描述符来检查就绪的描述符,这个过程的时间复杂度为O(N)。

      epoll没有select这样对文件描述符上限的限制,也不会像poll那样进行线性的遍历。因此epoll处理大并发连接有着更高的性能。

    Epoll相关操作函数介绍:

     1. epoll_create(2) or epoll_create1(2)(有着不同的参数值)用来创建epoll实例。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /usr/include/sys/epoll.h  
  2. extern int epoll_create (int __size) ;  
  3. RETURN:>0, 成功;-1, 出错  

函数描述:

       (1) epoll_create返回的是一个文件描述符,也就是说epoll是以特殊文件的方式体现给用户

       (2) __size提示操作系统,用户可能要使用多少个文件描述符,该参数已经废弃,填写一个大于0的正整数

      2.  epoll_ctl(2)用来增加或移除被epoll所监听的文件描述符。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int epoll_ctl(int epfd, int op, int fd, struct  epoll_event *event);  
  2. RETURN:0,成功;-1,出错  

函数描述:

        (1) epfd为epoll_create创建的epoll描述符

        (2) epoll_ctl函数对epoll进行op类型的操作,op选项为

              EPOLL_CTL_ADD,对fd描述符注册event事件

              EPOLL_CTL_MOD,对fd描述符的event事件进行修改

              EPOLL_CTL_DEL,删除已注册的event事件

      3. epoll_wait(2)用来等待发生在监听描述符上的事件。它会一直阻塞直到事件发生。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <sys/epoll.h>  
  2. int epoll_wait(int epfd, struct epoll_event *events,  
  3.                 int maxevents, int timeout);  
  4. RETURN:>0,发生事件个数;=0,时间到;-1,出错  

函数描述:

           epoll_wait与select函数类似,同步地等待事件发生

           (1) epfd,标识epoll的文件描述符

           (2) events,指向传入操作系统的一个epoll_event数组

           (3) maxevents,表示传入数组的大小,必须大于0

          当有事件发生,Linux会填写events结构,返回给应用程序。由于epoll_wait同步等待,有可能被信号中断,返回EINTR错误

      更多的函数介绍请参照man。  

Epoll的两种模式:

      1. 水平触发(LT):使用此种模式,当数据可读的时候,epoll_wait()将会一直返回就绪事件。如果你没有处理完全部数据,并且再次在该epoll实例上调用epoll_wait()才监听描述符的时候,它将会再次返回就绪事件,因为有数据可读。ET只支持非阻塞socket。

      2. 边缘触发(ET):使用此种模式,只能获取一次就绪通知,如果没有处理完全部数据,并且再次调用epoll_wait()的时候,它将会阻塞,因为就绪事件已经释放出来了。

ET的效能更高,但是对程序员的要求也更高。在ET模式下,我们必须一次干净而彻底地处理完所有事件。LT两种模式的socket都支持。

     传递给epoll_ctl(2)的Epoll事件结构体如下所示:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. typedef union epoll_data  
  2. {  
  3. void* ptr;  
  4. int fd;  
  5.   __uint32_t   u32;  
  6.   __uint64_t   u64;  
  7. }epoll_data_t;  
  8.   
  9. struct epoll_event  
  10. {  
  11.   __uint32_t   events;/* Epoll events */  
  12. epoll_data_t data;/* User data variable */  
  13. };  

对于每一个监听的描述符,能够关联一个整形数据或指向用户数据的指针。

      epoll的事件类型:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. enum EPOLL_EVENTS  
  2.   {  
  3.     EPOLLIN = 0x001,  
  4. #define EPOLLIN EPOLLIN  
  5.     EPOLLPRI = 0x002,  
  6. #define EPOLLPRI EPOLLPRI  
  7.     EPOLLOUT = 0x004,  
  8. #define EPOLLOUT EPOLLOUT  
  9.     EPOLLRDNORM = 0x040,  
  10. #define EPOLLRDNORM EPOLLRDNORM  
  11.     EPOLLRDBAND = 0x080,  
  12. #define EPOLLRDBAND EPOLLRDBAND  
  13.     EPOLLWRNORM = 0x100,  
  14. #define EPOLLWRNORM EPOLLWRNORM  
  15.     EPOLLWRBAND = 0x200,  
  16. #define EPOLLWRBAND EPOLLWRBAND  
  17.     EPOLLMSG = 0x400,  
  18. #define EPOLLMSG EPOLLMSG  
  19.     EPOLLERR = 0x008,  
  20. #define EPOLLERR EPOLLERR  
  21.     EPOLLHUP = 0x010,  
  22. #define EPOLLHUP EPOLLHUP  
  23.     EPOLLRDHUP = 0x2000,  
  24. #define EPOLLRDHUP EPOLLRDHUP  
  25.     EPOLLONESHOT = (1 << 30),  
  26. #define EPOLLONESHOT EPOLLONESHOT  
  27.     EPOLLET = (1 << 31)  
  28. #define EPOLLET EPOLLET  
  29.   };  

– EPOLLIN,读事件

– EPOLLOUT,写事件

– EPOLLPRI,带外数据,与select的异常事件集合对应

– EPOLLRDHUP,TCP连接对端至少写写半关闭

– EPOLLERR,错误事件

– EPOLLET,设置事件为边沿触发

– EPOLLONESHOT,只触发一次,事件自动被删除

      epoll在一个文件描述符上只能有一个事件,在一个描述符上添加多个事件,会产生EEXIST的错误。同样,删除epoll的事件,只需描述符就够了

      epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);

      这里有一个比较重要的问题:从epoll_wait返回的events中,该如何知道是哪个描述符上的事件:在注册epoll事件的时候,一定要填写epoll_data,否则我们将分不清触发的是哪个描述符上的事件。

     下面我们将实现一个轻型TCP服务器,功能是在标准输出中打印发送给套接字的一切数据。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /* 
  2.  * ===================================================================================== 
  3.  * 
  4.  *       Filename:  EpollServer.c 
  5.  * 
  6.  *    Description:  this is a epoll server example 
  7.  * 
  8.  *        Version:  1.0 
  9.  *        Created:  2012年03月15日 20时24分26秒 
  10.  *       Revision:  none 
  11.  *       Compiler:  gcc 
  12.  * 
  13.  *         Author:  LGP (), lgp8819@gmail.com 
  14.  *        Company:   
  15.  * 
  16.  * ===================================================================================== 
  17.  */  
  18.   
  19. #include <stdio.h>  
  20. #include <stdlib.h>  
  21. #include <string.h>  
  22. #include <sys/epoll.h>  
  23. #include <sys/types.h>  
  24. #include <sys/socket.h>  
  25. #include <errno.h>  
  26. #include <fcntl.h>  
  27. #include <unistd.h>  
  28. #include <netdb.h>  
  29.   
  30. /*struct addrinfo  
  31. { 
  32.     int              ai_flags; 
  33.     int              ai_family; 
  34.     int              ai_socktype; 
  35.     int              ai_protocol; 
  36.     size_t           ai_addrlen; 
  37.     struct sockaddr *ai_addr; 
  38.     char            *ai_canonname; 
  39.     struct addrinfo *ai_next; 
  40. }; */  
  41.   
  42. static int create_and_bind(char* port)  
  43. {  
  44.     struct addrinfo hints;  
  45.     struct addrinfo*result,*rp;  
  46.     int s,sfd;  
  47.   
  48.     memset(&hints,0,sizeof(struct addrinfo));  
  49.     hints.ai_family= AF_UNSPEC;/* Return IPv4 and IPv6 */  
  50.     hints.ai_socktype= SOCK_STREAM;/* TCP socket */  
  51.     hints.ai_flags= AI_PASSIVE;/* All interfaces */  
  52.   
  53.     s = getaddrinfo(NULL, port,&hints,&result); //more info about getaddrinfo() please see:man getaddrinfo!  
  54.     if(s != 0)  
  55.     {  
  56.         fprintf(stderr,"getaddrinfo: %s\n",gai_strerror(s));  
  57.         return -1;  
  58.     }  
  59.     for(rp= result;rp!= NULL;rp=rp->ai_next)  
  60.     {  
  61.         sfd = socket(rp->ai_family,rp->ai_socktype,rp->ai_protocol);  
  62.         if(sfd==-1)  
  63.             continue;  
  64.         s =bind(sfd,rp->ai_addr,rp->ai_addrlen);  
  65.         if(s ==0)  
  66.         {  
  67.             /* We managed to bind successfully! */  
  68.             break;  
  69.         }  
  70.         close(sfd);  
  71.     }  
  72.   
  73.     if(rp== NULL)  
  74.     {  
  75.         fprintf(stderr,"Could not bind\n");  
  76.         return-1;  
  77.     }  
  78.     freeaddrinfo(result);  
  79.     return sfd;  
  80. }  
  81.   
  82. static int make_socket_non_blocking(int sfd)  
  83. {  
  84.     int flags, s;  
  85.     flags = fcntl(sfd, F_GETFL,0);  
  86.     if(flags == -1)  
  87.     {  
  88.         perror("fcntl");  
  89.         return-1;  
  90.     }  
  91.   
  92.     flags|= O_NONBLOCK;  
  93.     s =fcntl(sfd, F_SETFL, flags);  
  94.     if(s ==-1)  
  95.     {  
  96.         perror("fcntl");  
  97.         return-1;  
  98.     }  
  99.     return 0;  
  100. }  
  101.   
  102.   
  103. #define MAXEVENTS 64  
  104. int main(int argc,char*argv[])  
  105. {  
  106.     int sfd, s;  
  107.     int efd;  
  108.     struct epoll_event event;  
  109.     struct epoll_event* events;  
  110.   
  111.     if(argc!=2)  
  112.     {  
  113.         fprintf(stderr,"Usage: %s [port]\n",argv[0]);  
  114.         exit(EXIT_FAILURE);  
  115.     }  
  116.   
  117.     sfd = create_and_bind(argv[1]);  
  118.     if( sfd == -1 )  
  119.         abort();  
  120.   
  121.     s = make_socket_non_blocking(sfd);  
  122.     if(s ==-1)  
  123.         abort();  
  124.   
  125.     s = listen(sfd, SOMAXCONN);  
  126.     if(s ==-1)  
  127.     {  
  128.         perror("listen");  
  129.         abort();  
  130.     }  
  131.   
  132.     efd = epoll_create1(0);  
  133.     if(efd==-1)  
  134.     {  
  135.         perror("epoll_create");  
  136.         abort();  
  137.     }  
  138.   
  139.     event.data.fd=sfd;  
  140.     event.events= EPOLLIN | EPOLLET;  
  141.     s =epoll_ctl(efd, EPOLL_CTL_ADD,sfd,&event);  
  142.     if(s ==-1)  
  143.     {  
  144.         perror("epoll_ctl");  
  145.         abort();  
  146.     }  
  147.   
  148.     /* Buffer where events are returned */  
  149.     events=calloc(MAXEVENTS,sizeof event);  
  150.   
  151.     /* The event loop */  
  152.     while(1)  
  153.     {  
  154.         int n,i;  
  155.         n =epoll_wait(efd, events, MAXEVENTS,-1);  
  156.         for(i=0;i< n;i++)  
  157.         {  
  158.             if((events[i].events & EPOLLERR)||  
  159.                     (events[i].events & EPOLLHUP)||  
  160.                     (!(events[i].events & EPOLLIN)))  
  161.             {  
  162.                 /* An error has occured on this fd, or the socket is not 
  163.                    ready for reading (why were we notified then?) */  
  164.                 fprintf(stderr,"epoll error\n");  
  165.                 close(events[i].data.fd);  
  166.                 continue;  
  167.             }  
  168.   
  169.             else if(sfd == events[i].data.fd)  
  170.             {  
  171.                 /* We have a notification on the listening socket, which 
  172.                    means one or more incoming connections. */  
  173.                 while(1)  
  174.                 {  
  175.                     struct sockaddr in_addr;  
  176.                     socklen_t in_len;  
  177.                     int infd;  
  178.                     char hbuf[NI_MAXHOST],sbuf[NI_MAXSERV];  
  179.   
  180.                     in_len = sizeof in_addr;  
  181.                     infd = accept(sfd,&in_addr,&in_len);  
  182.                     if(infd==-1)  
  183.                     {  
  184.                         if((errno== EAGAIN)||  
  185.                                 (errno== EWOULDBLOCK))  
  186.                         {  
  187.                             /* We have processed all incoming 
  188.                                connections. */  
  189.                             break;  
  190.                         }  
  191.                         else  
  192.                         {  
  193.                             perror("accept");  
  194.                             break;  
  195.                         }  
  196.                     }  
  197.   
  198.                     s =getnameinfo(&in_addr,in_len,  
  199.                             hbuf,sizeof hbuf,  
  200.                             sbuf,sizeof sbuf,  
  201.                             NI_NUMERICHOST | NI_NUMERICSERV);  
  202.                     if(s ==0)  
  203.                     {  
  204.                         printf("Accepted connection on descriptor %d "  
  205.                                 "(host=%s, port=%s)\n",infd,hbuf,sbuf);  
  206.                     }  
  207.   
  208.                     /* Make the incoming socket non-blocking and add it to the 
  209.                        list of fds to monitor. */  
  210.                     s = make_socket_non_blocking(infd);  
  211.                     if(s ==-1)  
  212.                         abort();  
  213.   
  214.                     event.data.fd=infd;  
  215.                     event.events= EPOLLIN | EPOLLET;  
  216.                     s = epoll_ctl(efd, EPOLL_CTL_ADD,infd,&event);  
  217.                     if(s ==-1)  
  218.                     {  
  219.                         perror("epoll_ctl");  
  220.                         abort();  
  221.                     }  
  222.                 }  
  223.                 continue;  
  224.             }  
  225.             else  
  226.             {  
  227.                 /* We have data on the fd waiting to be read. Read and 
  228.                    display it. We must read whatever data is available 
  229.                    completely, as we are running in edge-triggered mode 
  230.                    and won't get a notification again for the same 
  231.                    data. */  
  232.                 int done =0;  
  233.                 while(1)  
  234.                 {  
  235.                     ssize_t count;  
  236.                     char buf[512];  
  237.                     count = read(events[i].data.fd,buf,sizeof buf);  
  238.                     if(count == -1)  
  239.                     {  
  240.                         /* If errno == EAGAIN, that means we have read all 
  241.                            data. So go back to the main loop. */  
  242.                         if(errno!= EAGAIN)  
  243.                         {  
  244.                             perror("read");  
  245.                             done=1;  
  246.                         }  
  247.                         break;  
  248.                     }  
  249.                     else if(count ==0)  
  250.                     {  
  251.                         /* End of file. The remote has closed the 
  252.                            connection. */  
  253.                         done=1;  
  254.                         break;  
  255.                     }  
  256.                     /* Write the buffer to standard output */  
  257.                     s = write(1,buf, count);  
  258.                     if(s ==-1)  
  259.                     {  
  260.                         perror("write");  
  261.                         abort();  
  262.                     }  
  263.                 }  
  264.                 if(done)  
  265.                 {  
  266.                     printf("Closed connection on descriptor %d\n",events[i].data.fd);  
  267.                     /* Closing the descriptor will make epoll remove it 
  268.                        from the set of descriptors which are monitored. */  
  269.                     close(events[i].data.fd);  
  270.                 }  
  271.             }  
  272.         }  
  273.     }  
  274.     free(events);  
  275.     close(sfd);  
  276.     return EXIT_SUCCESS;  
  277. }  

 以下是使用c++对epoll简单的封装类:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * @file file.h 
  3.  * @comment 
  4.  * wrap of file descriptor 
  5.  * 
  6.  * @author niexw 
  7.  */  
  8.   
  9. #ifndef _XCOM_FILE_H_  
  10. #define _XCOM_FILE_H_  
  11.   
  12. #include <stdio.h>  
  13. #include <fcntl.h>  
  14. #include <sys/uio.h>  
  15. #include <fcntl.h>  
  16. #include "exception.h"  
  17. #include "buffer.h"  
  18.   
  19. namespace unp  
  20. {  
  21.   
  22. /** 
  23.  * @class File 
  24.  * @comment 
  25.  * wrap of file descriptor 
  26.  */  
  27. class File  
  28. {  
  29. protected:  
  30.     int fd_;  
  31.   
  32. public:  
  33.     //  
  34.     // construtor and destructor  
  35.     //  
  36.     File() : fd_(-1) {}  
  37.     explicit File(FILE *stream) : fd_(fileno(stream)) {}  
  38.     ~File()  
  39.     { close(); }  
  40.   
  41.     int getFd() { return fd_; }  
  42.     int getFd() const { return fd_; }  
  43.   
  44.     size_t read(char *buf, size_t count) const  
  45.     {  
  46.         int ret;  
  47.         RETRY:  
  48.         if ((ret = ::read(fd_, buf, count)) == -1)  
  49.         {  
  50.             if (errno == EAGAIN)  
  51.                 goto RETRY;  
  52.             else  
  53.                 throw EXCEPTION();  
  54.         }  
  55.         return ret;  
  56.     }  
  57.   
  58.     size_t write(char *buf, size_t count) const  
  59.     {  
  60.         int ret;  
  61.         RETRY:  
  62.         if ((ret = ::write(fd_, buf, count)) == -1)  
  63.         {  
  64.             if (errno == EAGAIN)  
  65.                 goto RETRY;  
  66.             else  
  67.                 throw EXCEPTION();  
  68.         }  
  69.         return ret;  
  70.     }  
  71.   
  72.     void close()  
  73.     {  
  74.         if (fd_ != -1) {  
  75.             ::close(fd_);  
  76.             fd_ = -1;  
  77.         }  
  78.     }  
  79.   
  80.     void setNonblock()  
  81.     {  
  82.         int flags = fcntl(fd_, F_GETFL);  
  83.         if (flags == -1)  
  84.             throw EXCEPTION();  
  85.         flags |= O_NONBLOCK;  
  86.         flags = fcntl(fd_, F_SETFL, flags);  
  87.         if (flags == -1)  
  88.             throw EXCEPTION();  
  89.     }  
  90.   
  91.     void clrNonblock()  
  92.     {  
  93.         int flags = fcntl(fd_, F_GETFL);  
  94.         if (flags == -1)  
  95.             throw EXCEPTION();  
  96.         flags &= ~O_NONBLOCK;  
  97.         flags = fcntl(fd_, F_SETFL, flags);  
  98.         if (flags == -1)  
  99.             throw EXCEPTION();  
  100.     }  
  101.   
  102.     size_t readv(CircleBuffer &buf)  
  103.     {  
  104.         int ret;  
  105.         RETRY:  
  106.         if ((ret = ::readv(fd_, buf.idle_, buf.idlenum_)) == -1)  
  107.         {  
  108.             if (errno == EAGAIN)  
  109.                 goto RETRY;  
  110.             else  
  111.                 throw EXCEPTION();  
  112.         }  
  113.         buf.afterRead(ret);  
  114.         return ret;  
  115.     }  
  116.   
  117.     size_t writev(CircleBuffer &buf)  
  118.     {  
  119.         int ret;  
  120.         RETRY:  
  121.         if ((ret = ::writev(fd_, buf.data_, buf.datanum_)) == -1)  
  122.         {  
  123.             if (errno == EAGAIN)  
  124.                 goto RETRY;  
  125.             else  
  126.                 throw EXCEPTION();  
  127.         }  
  128.         buf.afterWrite(ret);  
  129.         return ret;  
  130.     }  
  131.   
  132.     void setFlag(int option)  
  133.     {  
  134.         int flags;  
  135.         RETRY:  
  136.         flags = fcntl(fd_, F_GETFL);  
  137.         if (flags == -1) {  
  138.             if (errno == EINTR)  
  139.                 goto RETRY;  
  140.             else  
  141.                 throw EXCEPTION();  
  142.         }  
  143.         flags |= option;  
  144.         RETRY1:  
  145.         int ret = fcntl(fd_, F_SETFL, flags);  
  146.         if (ret == -1) {  
  147.             if (errno == EINTR)  
  148.                 goto RETRY1;  
  149.             else  
  150.                 throw EXCEPTION();  
  151.         }  
  152.     }  
  153.   
  154.     void clrFlag(int option)  
  155.     {  
  156.         int flags;  
  157.         RETRY:  
  158.         flags = fcntl(fd_, F_GETFL);  
  159.         if (flags == -1) {  
  160.             if (errno == EINTR)  
  161.                 goto RETRY;  
  162.             else  
  163.                 throw EXCEPTION();  
  164.         }  
  165.         flags &= ~option;  
  166.         RETRY1:  
  167.         int ret = fcntl(fd_, F_SETFL, flags);  
  168.         if (ret == -1) {  
  169.             if (errno == EINTR)  
  170.                 goto RETRY1;  
  171.             else  
  172.                 throw EXCEPTION();  
  173.         }  
  174.     }  
  175.   
  176. };  
  177.   
  178. /** 
  179.  * @class File2 
  180.  * @comment 
  181.  * wrap of file descriptor 
  182.  */  
  183. class File2  
  184. {  
  185. protected:  
  186.     int descriptor_;  
  187.   
  188. public:  
  189.     File2() : descriptor_(-1)  
  190.     { }  
  191.     explicit File2(FILE *stream) : descriptor_(fileno(stream))  
  192.     { }  
  193.     explicit File2(File2 &f) : descriptor_(f.descriptor_)  
  194.     { f.descriptor_ = -1; }  
  195.     ~File2()  
  196.     { close(); }  
  197.   
  198.     int descriptor() { return descriptor_; }  
  199.   
  200.     size_t read(char *buf, size_t count)  
  201.     {  
  202.         int ret;  
  203.         RETRY:  
  204.         if ((ret = ::read(descriptor_, buf, count)) == -1)  
  205.         {  
  206.             if (errno == EAGAIN)  
  207.                 goto RETRY;  
  208.             else  
  209.                 throw EXCEPTION();  
  210.         }  
  211.         return ret;  
  212.     }  
  213.   
  214.     size_t write(char *buf, size_t count) const  
  215.     {  
  216.         int ret;  
  217.         RETRY:  
  218.         if ((ret = ::write(descriptor_, buf, count)) == -1)  
  219.         {  
  220.             if (errno == EAGAIN)  
  221.                 goto RETRY;  
  222.             else  
  223.                 throw EXCEPTION();  
  224.         }  
  225.         return ret;  
  226.     }  
  227.   
  228.     void close()  
  229.     {  
  230.         if (descriptor_ != -1) {  
  231.             ::close(descriptor_);  
  232.             descriptor_ = -1;  
  233.         }  
  234.     }  
  235.   
  236.     size_t readv(const struct iovec *iov, int cnt)  
  237.     {  
  238.         int ret;  
  239.         RETRY:  
  240.         if ((ret = ::readv(descriptor_, iov, cnt)) == -1)  
  241.         {  
  242.             if (errno == EAGAIN)  
  243.                 goto RETRY;  
  244.             else  
  245.                 throw EXCEPTION();  
  246.         }  
  247.         return ret;  
  248.     }  
  249.   
  250.     size_t writev(const struct iovec *iov, int cnt)  
  251.     {  
  252.         int ret;  
  253.         RETRY:  
  254.         if ((ret = ::writev(descriptor_, iov, cnt)) == -1)  
  255.         {  
  256.             if (errno == EAGAIN)  
  257.                 goto RETRY;  
  258.             else  
  259.                 throw EXCEPTION();  
  260.         }  
  261.         return ret;  
  262.     }  
  263.   
  264.     void setControlOption(int option)  
  265.     {  
  266.         int flags;  
  267.         RETRY:  
  268.         flags = fcntl(descriptor_, F_GETFL);  
  269.         if (flags == -1) {  
  270.             if (errno == EINTR)  
  271.                 goto RETRY;  
  272.             else  
  273.                 throw EXCEPTION();  
  274.         }  
  275.         flags |= option;  
  276.         RETRY1:  
  277.         int ret = fcntl(descriptor_, F_SETFL, flags);  
  278.         if (ret == -1) {  
  279.             if (errno == EINTR)  
  280.                 goto RETRY1;  
  281.             else  
  282.                 throw EXCEPTION();  
  283.         }  
  284.     }  
  285.   
  286.     void clearControlOption(int option)  
  287.     {  
  288.         int flags;  
  289.         RETRY:  
  290.         flags = fcntl(descriptor_, F_GETFL);  
  291.         if (flags == -1) {  
  292.             if (errno == EINTR)  
  293.                 goto RETRY;  
  294.             else  
  295.                 throw EXCEPTION();  
  296.         }  
  297.         flags &= ~option;  
  298.         RETRY1:  
  299.         int ret = fcntl(descriptor_, F_SETFL, flags);  
  300.         if (ret == -1) {  
  301.             if (errno == EINTR)  
  302.                 goto RETRY1;  
  303.             else  
  304.                 throw EXCEPTION();  
  305.         }  
  306.     }  
  307.   
  308.     void setNonblock()  
  309.     {  
  310.         int flags = fcntl(descriptor_, F_GETFL);  
  311.         if (flags == -1)  
  312.             throw EXCEPTION();  
  313.         flags |= O_NONBLOCK;  
  314.         flags = fcntl(descriptor_, F_SETFL, flags);  
  315.         if (flags == -1)  
  316.             throw EXCEPTION();  
  317.     }  
  318.   
  319.     void clrNonblock()  
  320.     {  
  321.         int flags = fcntl(descriptor_, F_GETFL);  
  322.         if (flags == -1)  
  323.             throw EXCEPTION();  
  324.         flags &= ~O_NONBLOCK;  
  325.         flags = fcntl(descriptor_, F_SETFL, flags);  
  326.         if (flags == -1)  
  327.             throw EXCEPTION();  
  328.     }  
  329.   
  330.   
  331. };  
  332.   
  333. }; // namespace unp  
  334. #endif // _XCOM_FILE_H_  
  335.   
  336. /** 
  337.  * @file epoll.h 
  338.  * @comment 
  339.  * wrap of epoll 
  340.  * 
  341.  * @author niexw 
  342.  */  
  343.   
  344. #ifndef _UNP_EPOLL_H_  
  345. #define _UNP_EPOLL_H_  
  346.   
  347. #include <sys/epoll.h>  
  348. #include <assert.h>  
  349. #include <map>  
  350. #include <strings.h>  
  351. #include "file.h"  
  352.   
  353. namespace unp  
  354. {  
  355.   
  356. /** 
  357.  * @class Epoll 
  358.  * @comment 
  359.  * wrap of epoll 
  360.  */  
  361. class Epoll : public File  
  362. {  
  363. public:  
  364.     Epoll() {}  
  365.     ~Epoll() {}  
  366.   
  367.     struct Event : public epoll_event  
  368.     {  
  369.         Event() { events = EPOLLERR; data.u64 = 0; }  
  370.         Event(unsigned int type, void *magic)  
  371.         { events = type; data.ptr = magic; }  
  372.     };  
  373.   
  374.     int create()  
  375.     {  
  376.         if ((fd_ = epoll_create(1)) == -1)  
  377.             throw EXCEPTION();  
  378.         return fd_;  
  379.     }  
  380.   
  381.     void registerEvent(int fd, Event &event)  
  382.     {  
  383.         if (epoll_ctl(fd_, EPOLL_CTL_ADD, fd, &event) == -1)  
  384.             throw EXCEPTION();  
  385.     }  
  386.   
  387.     void modifyEvent(int fd, Event &event)  
  388.     {  
  389.         if (epoll_ctl(fd_, EPOLL_CTL_MOD, fd, &event) == -1)  
  390.             throw EXCEPTION();  
  391.     }  
  392.   
  393.     void unregisterEvent(int fd)  
  394.     {  
  395.         if (epoll_ctl(fd_, EPOLL_CTL_DEL, fd, NULL) == -1)  
  396.             throw EXCEPTION();  
  397.     }  
  398.   
  399.     int waitEvent(Event *events, int size, int msec)  
  400.     {  
  401.         int ret;  
  402.         assert(events != NULL);  
  403.         RETRY:  
  404.         if ((ret = epoll_wait(fd_, events, size,  
  405.                 msec == -1 ? NULL : msec)) == -1)  
  406.         {  
  407.             if (errno == EINTR)  
  408.                 goto RETRY;  
  409.             else  
  410.                 throw EXCEPTION();  
  411.         }  
  412.         return ret;  
  413.     }  
  414. };  
  415.   
  416. #include <iostream>  
  417. using std::cout;  
  418. using std::endl;  
  419.   
  420. class Epoll2 : public File  
  421. {  
  422. public:  
  423.     typedef void* (*Callback)(epoll_event &event, void *);  
  424.   
  425. protected:  
  426.     struct Event : public epoll_event  
  427.     {  
  428.         Callback func_;  
  429.         void *param_;  
  430.   
  431.         Event() : func_(NULL), param_(NULL)  
  432.         { events = EPOLLERR; data.u64 = 0; }  
  433.         Event(unsigned int type) : func_(NULL), param_(NULL)  
  434.         { events = EPOLLERR | type; data.u64 = 0; }  
  435.         Event(unsigned int type, Callback func, void *param)  
  436.             : func_(func), param_(param)  
  437.         { events = EPOLLERR | type; data.u64 = 0; }  
  438.     };  
  439.     typedef std::map<int, Event> Events;  
  440.   
  441.     Events events_;  
  442.     epoll_event happens_[10];  
  443.   
  444.     int timeout_;  
  445.     Callback func_;  
  446.     void *param_;  
  447.   
  448. public:  
  449.     Epoll2() : timeout_(-1), func_(NULL), param_(NULL)  
  450.     {  
  451.         assert(sizeof(Events::iterator) == sizeof(void*));  
  452.         fd_ = epoll_create(10);  
  453.     }  
  454.   
  455.     Epoll2(int msec, Callback func) : timeout_(msec), func_(NULL), param_(NULL)  
  456.     {  
  457.          assert(sizeof(Events::iterator) == sizeof(void*));  
  458.          fd_ = epoll_create(10);  
  459.     }  
  460.   
  461.     ~Epoll2()  
  462.     { }  
  463.   
  464.     void registerEvent(int fd, int option, Callback func, void *param)  
  465.     {  
  466.         Event event(option, func, param);  
  467.         std::pair<Events::iterator, bool> ret =  
  468.                 events_.insert(std::pair<int, Event>(fd, event));  
  469.         //ret.first->second.data.ptr = (void *)ret.first._M_node;  
  470.         bcopy(&ret.first, &ret.first->second.data.ptr, sizeof(void*));  
  471.         if (epoll_ctl(fd_, EPOLL_CTL_ADD, fd, &ret.first->second) == -1)  
  472.             throw EXCEPTION();  
  473.     }  
  474.   
  475.     void setEventOption(int fd, int option)  
  476.     {  
  477.         Event *p = &events_[fd];  
  478.         p->events = option | EPOLLERR;  
  479.         if (epoll_ctl(fd_, EPOLL_CTL_MOD, fd, p) == -1)  
  480.             throw EXCEPTION();  
  481.     }  
  482.   
  483.     void setEventOption(int fd, int option, Callback func, void *param)  
  484.     {  
  485.         Event *p = &events_[fd];  
  486.         p->events = option | EPOLLERR;  
  487.         p->func_ = func;  
  488.         p->param_ = param;  
  489.         if (epoll_ctl(fd_, EPOLL_CTL_MOD, fd, p) == -1)  
  490.             throw EXCEPTION();  
  491.     }  
  492.   
  493.     void addEventOption(int fd, int option)  
  494.     {  
  495.         Event *p = &events_[fd];  
  496.         p->events |= option;  
  497.         if (epoll_ctl(fd_, EPOLL_CTL_MOD, fd, p) == -1)  
  498.             throw EXCEPTION();  
  499.     }  
  500.   
  501.     void addEventOption(int fd, int option, Callback func, void *param)  
  502.     {  
  503.         Event *p = &events_[fd];  
  504.         p->events |= option;  
  505.         p->func_ = func;  
  506.         p->param_ = param;  
  507.         if (epoll_ctl(fd_, EPOLL_CTL_MOD, fd, p) == -1)  
  508.             throw EXCEPTION();  
  509.     }  
  510.   
  511.     void clrEventOption(int fd, int option, Callback func, void *param)  
  512.     {  
  513.         Event *p = &events_[fd];  
  514.         p->events &= ~option;  
  515.         p->func_ = func;  
  516.         p->param_ = param;  
  517.         if (epoll_ctl(fd_, EPOLL_CTL_MOD, fd, p) == -1)  
  518.             throw EXCEPTION();  
  519.     }  
  520.   
  521.     void clrEventOption(int fd, int option)  
  522.     {  
  523.         Event *p = &events_[fd];  
  524.         p->events &= ~option;  
  525.         if (epoll_ctl(fd_, EPOLL_CTL_MOD, fd, p) == -1)  
  526.             throw EXCEPTION();  
  527.     }  
  528.   
  529.     void unregisterEvent(int fd)  
  530.     {  
  531.         events_.erase(fd);  
  532.         if (epoll_ctl(fd_, EPOLL_CTL_DEL, fd, NULL) == -1)  
  533.             throw EXCEPTION();  
  534.     }  
  535.   
  536.     void setTimeout(int msec, Callback func, void *param)  
  537.     {  
  538.         timeout_ = msec;  
  539.         func_ = func;  
  540.         param_ = param;  
  541.     }  
  542.   
  543.     bool run()  
  544.     {  
  545.         int ret;  
  546.         RETRY:  
  547.         if ((ret = epoll_wait(fd_, happens_, 10, timeout_)) == -1)  
  548.         {  
  549.             if (errno == EINTR)  
  550.                 goto RETRY;  
  551.             else  
  552.                 throw EXCEPTION();  
  553.         }  
  554.   
  555.         for (int i = 0; i < ret; ++i)  
  556.         {  
  557.             Events::iterator it;  
  558.             bcopy(&happens_[i].data.ptr, &it, sizeof(void *));  
  559.             //it._M_node = (std::_Rb_tree_node_base*)happens_[i].data.ptr;  
  560.             if (it->second.func_ != NULL)  
  561.                 it->second.func_(happens_[i], it->second.param_);  
  562.             if (happens_[i].events & EPOLLERR)  
  563.                 throw EXCEPTION();  
  564.         }  
  565.   
  566.         if (ret == 0 && func_ != NULL)  
  567.             func_(happens_[0], param_);  
  568.   
  569.         return !events_.empty();  
  570.     }  
  571.   
  572. };  
  573.   
  574.   
  575. }; // namespace unp  
  576. #endif /* _UNP_EPOLL_H_ */  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值