Chinaunix首页 | 论坛 | 博客
  • 博客访问: 79312
  • 博文数量: 83
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 20
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-30 00:36
文章分类

全部博文(83)

文章存档

2014年(83)

我的朋友

分类: C/C++

2014-07-17 14:39:46

原文地址:epoll example - ET - LT 作者:bjpiao

LT模式:epoll就是一个快速版poll,可读可写就绪条件和传统poll一致
ET模式:为了避免Starvation,建议 
         1)文件描述符设置为非阻塞 
         2)只在read或write返回EAGAIN后,才能调用下一次epoll_wait 
         3)应用层维护一个就绪链表,进行轮询,可以防止大量IO时在一个描述符上长期read或write(因为只有等到read或 write返回EAGAIN后才               表示该描述符处理完毕)而令其它描述符starve
      理解ET的含义后,上面那些操作其实都是显然的。以wirte为例说明,LT时只要有一定范围的空闲写缓存区,每次epoll_wait都是可写条件就 绪,但是ET时从第一次可写就绪后,epoll_wait不再得到该描述符可写就绪通知直到程序使描述符变为非可写就绪(比如write收到 EAGAIN)后,epoll_wait才可能继续收到可写就绪通知(比如有空闲可写缓存)
      其实ET相对于LT来说,把文件描述符状态跟踪的部分责任由内核空间推到用户空间,内核只关心状态切换即从未就绪到就绪切换时才通知用户,至于保持就绪 状态的,内核不再通知用户,这样在实现非阻塞模型时更方便,不需要每次操作都先查看文件描述符状态。

使用linux epoll模型,水平触发模式(Level-Triggered), 当socket可写时,会不停的触发socket可写的事件,如何处理?

1. 当需要向socket写数据时,将该socket加入到epoll模型(epoll_ctl), 等待可写事件。接收到socket可写事件后,调用write()或send()发送数据。当数据全部写完后, 将socket描述符移出epoll模型。

这种方式的缺点是: 即使发送很少的数据,也要将socket加入、移出epoll模型。有一定的操作代价。

2. 向socket写数据时,不将socket加入到epoll模型;而是直接调用send()发送; 只有当或send()返回错误码EAGAIN(系统缓存满),才将socket加入到epoll模型,等待可写事件后,再发送数据。

全部数据发送完毕,再移出epoll模型。这种方案的优点: 当用户数据比较少时,不需要epool的事件处理。 

3. 使用Edge-Triggered(边沿触发),这样socket有可写事件,只会触发一次。 可以在应用层做好标记。以避免频繁的调用 epoll_ctl( EPOLL_CTL_ADD, EPOLL_CTL_MOD)。这种方式是epoll的man手册里推荐的方式,性能最高。但如果处理不当容易出错,事件驱动停止。

4. 在epoll_ctl()使用EPOLLONESHOT标志,当事件触发以后,socket会被禁止再次触发。需要再次调用epoll_ctl(EPOLL_CTL_MOD), 才会接收下一次事件。这种方式可以禁止socket可写事件,应该也会同时禁止可读事件。会带来不便,同时并没有性能优势,因为epoll_ctl有一定的操作代价。

5. 在有些情况下,为了避免针对一个fd读取的字节数量过大而导致影响其他fd的处理,ET模式server并不会读完所以的数据,但是未读完的数据并不会引起fd handler被再此调用,除非有新的数据到来。这时可以先设置fd为可writable,这会使得该fd在下一次epoll_wait时被在此唤醒,此时可以将未读完数据读完。


Server代码

点击(此处)折叠或打开

  1. #include
  2. #include

  3. #include
  4. #include
  5. #include

  6. #include
  7. #include
  8. #include
  9. #include
  10. #include

  11. #include
  12. #include"stdio.h"
  13. #include"stdlib.h"
  14. #include
  15. #include
  16. #include
  17. #include
  18. #include
  19. #include
  20. #include
  21. #include
  22. #include
  23. #include
  24. #include
  25. #include
  26. #include
  27. #include
  28. #include

  29. using namespace std;

  30. intep;
  31. struct epoll_event*event;
  32. intnevent;

  33.     int
  34. event_init(intsize)
  35. {
  36.     intstatus;

  37.     ep=epoll_create(size);
  38.     if(ep<0){
  39.         return-1;
  40.     }
  41.     nevent=size;

  42.     event=(struct epoll_event*)malloc(sizeof(struct epoll_event)*size);
  43.     if(event==NULL){
  44.         status=close(ep);
  45.         return-1;
  46.     }

  47.     memset(event,0,sizeof(struct epoll_event)*size);
  48.     return 0;
  49. }


  50.     int
  51. event_add_conn(intsd)
  52. {
  53.     intstatus;
  54.     struct epoll_event event;

  55.     //event.events=(uint32_t)(EPOLLIN|EPOLLOUT|EPOLLET);
  56.     //event.events=(uint32_t)(EPOLLIN|EPOLLOUT);
  57.     event.events=(uint32_t)(EPOLLIN);
  58.     event.data.fd=sd;

  59.     status=epoll_ctl(ep,EPOLL_CTL_ADD,sd,&event);
  60.     if(status<0)
  61.         printf("error: %s\n",strerror(errno));
  62.     return status;
  63. }


  64.     int
  65. event_del_conn(intsd)
  66. {
  67.     intstatus;

  68.     status=epoll_ctl(ep,EPOLL_CTL_DEL,sd,NULL);
  69.     if(status<0){
  70.         cout<<"del error"<
  71.     }

  72.     return status;
  73. }

  74. int
  75. event_add_out(intsd)
  76. {
  77.     intstatus;
  78.     struct epoll_event event;

  79.     event.events=(uint32_t)(EPOLLIN|EPOLLOUT);
  80.     //event.events=(uint32_t)(EPOLLIN|EPOLLOUT|EPOLLET);
  81.     event.data.fd=sd;

  82.     status=epoll_ctl(ep,EPOLL_CTL_MOD,sd,&event);
  83.     if(status<0){
  84.     return-1;
  85.     }

  86.     return status;
  87. }

  88. int
  89. event_del_out(intsd)
  90. {
  91.     intstatus;
  92.     struct epoll_event event;

  93.     event.events=(uint32_t)(EPOLLIN);
  94.     //event.events=(uint32_t)(EPOLLIN|EPOLLET);
  95.     event.data.fd=sd;

  96.     status=epoll_ctl(ep,EPOLL_CTL_MOD,sd,&event);
  97.     if(status<0){
  98.     return-1;
  99.     }

  100.     return status;
  101. }

  102.     int
  103. event_wait(inttimeout)
  104. {
  105.     intnsd;

  106.     for(;;){
  107.         nsd=epoll_wait(ep,event,nevent,timeout);
  108.         if(nsd>0){
  109.             return nsd;
  110.         }

  111.         if(nsd==0){
  112.             if(timeout==-1){
  113.                 printf("timeout\n");
  114.                 return-1;
  115.             }

  116.             return 0;
  117.         }

  118.         if(errno==EINTR){
  119.             continue;
  120.         }
  121.         return-1;
  122.     }

  123.     return 0;
  124. }

  125. void setnonblocking(intsock)
  126. {
  127.     intopts;
  128.     opts=fcntl(sock,F_GETFL);
  129.     if(opts<0)
  130.     {
  131.         perror("fcntl(sock,GETFL)");
  132.         exit(1);
  133.     }
  134.     opts=opts|O_NONBLOCK;
  135.     if(fcntl(sock,F_SETFL,opts)<0)
  136.     {
  137.         perror("fcntl(sock,SETFL,opts)");
  138.         exit(1);
  139.     }
  140. }

  141. intlistenfd;
  142. #define SERV_PORT 10000


  143. int
  144. set_tcpnodelay(intsd)
  145. {
  146.     intnodelay;
  147.     socklen_tlen;

  148.     nodelay=1;
  149.     len=sizeof(nodelay);

  150.     return setsockopt(sd,IPPROTO_TCP,TCP_NODELAY,&nodelay,len);
  151. }


  152. intinit_server()
  153. {
  154.     struct sockaddr_in serveraddr;

  155.     listenfd=socket(AF_INET,SOCK_STREAM,0);
  156.     setnonblocking(listenfd);
  157.     bzero(&serveraddr,sizeof(serveraddr));
  158.     serveraddr.sin_family=AF_INET;
  159.     char*local_addr=(char*)"127.0.0.1";
  160.     inet_aton(local_addr,&(serveraddr.sin_addr));
  161.     serveraddr.sin_port=htons(SERV_PORT);
  162.     bind(listenfd,(sockaddr*)&serveraddr,sizeof(serveraddr));
  163.     listen(listenfd,1024);    
  164.     intret=event_add_conn(listenfd);
  165.     if(ret<0)
  166.         cout<<"error"<
  167.     return 0;
  168. }

  169. intprocess_handle()
  170. {
  171.     for(;;){
  172.         intfd=accept(listenfd,NULL,NULL);
  173.         if(fd<0){
  174.             if(errno==EINTR){
  175.                 cout<<"accept on not ready - eintr"<
  176.                 continue;
  177.             }

  178.             if(errno==EAGAIN||errno==EWOULDBLOCK){
  179.                 cout<<"accept on not ready - eagain"<
  180.                 return 0;
  181.             }

  182.             return-1;
  183.         }
  184.         elseif(fd>0)
  185.         {
  186.             setnonblocking(fd);
  187.             set_tcpnodelay(fd);
  188.             intret=event_add_conn(fd);
  189.             cout<<"accept: "<
  190.             if(ret<0)
  191.                 cout<<"error"<
  192.         }
  193.     }
  194. }

  195. intread_data(intfd)
  196. {

  197.     for(;;)
  198.     {
  199.         char c;
  200.         intn=read(fd,&c,1);
  201.         if(n>0)
  202.             cout<
  203.         elseif(n==0)
  204.         {
  205.             cout<<"eof"<
  206.             event_del_conn(fd);
  207.             close(fd);
  208.             return 0;
  209.         }
  210.         elseif(n<0)
  211.         {
  212.             if(errno==EINTR)
  213.                 continue;
  214.             elseif(errno==EAGAIN||errno==EWOULDBLOCK)
  215.             {
  216.                 cout<<"again"<
  217.                             return 0;    
  218.             }
  219.         }
  220.     }
  221.     
  222.     return 0;
  223. }

  224. intmain()
  225. {
  226.     intret=event_init(100);
  227.     if(ret<0)
  228.         cout<<"error"<

  229.     init_server();

  230.     while(1)
  231.     {
  232.         inttimeout=-1;
  233.         intnsd=event_wait(timeout);
  234.         if(nsd<=0)
  235.             continue;        

  236.         inti;    
  237.         
  238.         intready=0;
  239.         for(i=0;i
  240.         {
  241.             struct epoll_event*ev=&event[i];
  242.             intfd=(int)(ev->data.fd);
  243.             if(fd==listenfd){
  244.                 cout<<"listen"<
  245.                 process_handle();
  246.             }
  247.             else
  248.             {
  249.                 uint32_t events=ev->events;
  250.                 /*errortakes precedence over read|write*/
  251.                 if(events&EPOLLERR){
  252.                     printf("event error\n");
  253.                     break;
  254.                 }

  255.                 /*read takes precedence over write*/
  256.                 if(events&(EPOLLIN|EPOLLHUP)){
  257.                     printf("event in\n");
  258.                     read_data(fd);
  259.                     if(ready==1)
  260.                     {
  261.                         event_add_out(fd);
  262.                     }
  263.                 }
  264.             
  265.                 if(events&(EPOLLOUT|EPOLLHUP))
  266.                 {
  267.                     printf("event out");
  268.                     if(ready==0)
  269.                     {    
  270.                         event_del_out(fd);
  271.                     }
  272.                     else
  273.                     {
  274.                         //send_data(fd);
  275.                     }
  276.                     /*the output will be addedinEPOLLIN
  277.                     *handler*/
  278.                     break;
  279.                 }
  280.             }
  281.         }
  282.     }

  283.     return 0;
  284. }
Client代码

点击(此处)折叠或打开


  1. #include
  2. #include
  3. #include

  4. #include
  5. #include
  6. #include
  7. #include
  8. #include

  9. #include
  10. #include"stdio.h"
  11. #include"stdlib.h"
  12. #include
  13. #include
  14. #include
  15. #include
  16. #include
  17. #include
  18. #include
  19. #include
  20. #include
  21. #include
  22. #include
  23. #include
  24. #include
  25. #include
  26. #include

  27. using namespace std;

  28. #define SERV_PORT 10000

  29. void setblocking(intsock)
  30. {
  31.     intopts;
  32.     opts=fcntl(sock,F_GETFL);
  33.     if(opts<0)
  34.     {
  35.         perror("fcntl(sock,GETFL)");
  36.         exit(1);
  37.     }
  38.     
  39.     opts=opts&~O_NONBLOCK;
  40.     if(fcntl(sock,F_SETFL,opts)<0)
  41.     {
  42.         perror("fcntl(sock,SETFL,opts)");
  43.         exit(1);
  44.     }
  45. }

  46. intmain()
  47. {
  48.     struct sockaddr_in serveraddr;

  49.     intconnfd=socket(AF_INET,SOCK_STREAM,0);
  50.     bzero(&serveraddr,sizeof(serveraddr));
  51.     serveraddr.sin_family=AF_INET;
  52.     char*local_addr=(char*)"127.0.0.1";
  53.     inet_aton(local_addr,&(serveraddr.sin_addr));
  54.     serveraddr.sin_port=htons(SERV_PORT);
  55.     intstatus=connect(connfd,(sockaddr*)&serveraddr,sizeof(serveraddr));
  56.     if(status!=0){
  57.         if(errno==EINPROGRESS){
  58.             return 0;
  59.         }
  60.         return-1;
  61.     }

  62.     setblocking(connfd);
  63.     
  64.     char buffer[1024]={"songweisongweisongwei"};
  65.     intsize=write(connfd,buffer,strlen(buffer));
  66.     cout<<"size: "<
  67.     
  68.     sleep(5);
  69.     
  70.     size=write(connfd,buffer,strlen(buffer));
  71.         cout<<"size: "<

  72.     return 0;

阅读(367) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~