Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1557014
  • 博文数量: 347
  • 博客积分: 9328
  • 博客等级: 中将
  • 技术积分: 2680
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-29 23:45
文章分类

全部博文(347)

文章存档

2016年(1)

2013年(4)

2012年(207)

2011年(85)

2010年(50)

分类: C/C++

2012-11-17 21:59:10

原文:http://blog.csdn.net/huangdh79/article/details/5739037

网上已有很多关于这两个函数的效率问题的文章,在这里不再累述。

本文主要对两个函数的编程细节问题,进行分析。

epoll使用et模式。select使用非阻塞模式

共用代码

    1。设置句柄为非阻塞方式

  1. int setnonblocking(int sockfd)     
  2. {     
  3.     if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)        
  4.       return -1;  
  5.     return 0;     
  6. }    

    2。创建监听句柄并打开监听

  1. int create_listen_fd(void)  
  2. {  
  3.         #define SERV_PORT 9999  
  4.     int listenfd;  
  5.     struct sockaddr_in servaddr;  
  6.       
  7.     listenfd = socket(AF_INET, SOCK_STREAM, 0);  
  8.     if(listenfd == -1)  
  9.         return -1;  
  10.     memset(&servaddr, 0x00, sizeof(servaddr));  
  11.     servaddr.sin_family = AF_INET;  
  12.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  13.     servaddr.sin_port = htons(SERV_PORT);  
  14.       
  15.     if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)  
  16.         return -1;  
  17.     if(listen(listenfd, 5) == -1)  
  18.         return -1;  
  19.       
  20.     return listenfd;  
  21. }  

测试场景
     1。客户端发送数据后等待,服务器端不对到达数据进行读取。
          目的:测试如果有事件到达,但处理结束后管道内仍然有数据存留,各种i/o复用模式是否仍对此事件作出相应。
          结果:
                1)epoll在数据到达后被唤醒,处理完业务流程后(不对socket管道内数据进行读取),又被阻塞到epoll_wait上。
  1. int main(int argc, char** argv)  
  2. {  
  3.     int epfd, nfds;  
  4.     //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件  
  5.     struct epoll_event ev,events[20];  
  6.     int listenfd, connfd;  
  7.     char buf[100];  
  8.       
  9.     if((listenfd = create_listen_fd()) == -1)  
  10.     {  
  11.         printf("create_listen_fd error/n");  
  12.         return -1;  
  13.     }  
  14.       
  15.     if(setnonblocking(listenfd) == -1)  
  16.     {  
  17.         printf("set non block error/n");  
  18.         return -1;  
  19.     }  
  20.       
  21.     //创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。  
  22.     epfd = epoll_create(256);  
  23.     //设置与要处理的事件相关的文件描述符  
  24.     ev.data.fd = listenfd;  
  25.     //设置要处理的事件类型,当描述符可读时出发,出发方式为ET模式  
  26.     ev.events = EPOLLIN | EPOLLET;  
  27.     //注册epoll事件  
  28.     epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);  
  29.       
  30.     for(;;)  
  31.     {  
  32.         //等待epoll事件的发生  
  33.         nfds = epoll_wait(epfd, events, 20, -1);  
  34.         printf("up/n");  
  35.         for(int i = 0; i < nfds; i++)  
  36.         {  
  37.             if(events[i].data.fd==listenfd)  
  38.             {  
  39.                 connfd = accept(listenfd, NULL, NULL);  
  40.                 setnonblocking(connfd);  
  41.                 //设置用于读操作的文件描述符  
  42.                 ev.data.fd = connfd;  
  43.                 //设置用于注测的读操作事件  
  44.                 ev.events = EPOLLIN | EPOLLET;  
  45.                 //注册ev  
  46.                 epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);  
  47.             }  
  48.             else if(events[i].events & EPOLLIN)  
  49.             {  
  50.                 if ( (connfd = events[i].data.fd) < 0) continue;  
  51.                 //sleep(10);  
  52.                 while(false)  
  53.                 {  
  54.                     memset(buf, 0x00, 100);  
  55.                     int rn;  
  56.                     if((rn = read(connfd, buf, 10)) < 0)  
  57.                     {  
  58.                         if(errno == EAGAIN)  
  59.                         {  
  60.                             printf("read finish break/n");  
  61.                             break;  
  62.                         }  
  63.                     }  
  64.                     else if(rn == 0)  
  65.                     {  
  66.                         close(connfd);  
  67.                         epoll_ctl(epfd, EPOLL_CTL_DEL, connfd, NULL);  
  68.                         printf("close /n");  
  69.                         break;  
  70.                     }  
  71.                     printf("read buf %s/n", buf);  
  72.                 }  
  73.             }  
  74.         }  
  75.     }  
  76.       
  77.     return 0;  
  78. }  
  
                2)select在数据到达后被唤醒,处理完业务流程后(不对socket管道内数据进行读取),select会再次被唤醒。

  1. int main(int argc, char** argv)  
  2. {  
  3.     #define HANDLE_CONNFD_COUNT 100  
  4.     int connfdSet[HANDLE_CONNFD_COUNT];  
  5.     fd_set rset,allset;  
  6.     int listenfd, connfd;  
  7.     int nfds;  
  8.     int iMax;  
  9.     char buf[100];  
  10.       
  11.     for(int i = 0; i < HANDLE_CONNFD_COUNT; i++)  
  12.     {  
  13.         connfdSet[i] = -1;  
  14.     }  
  15.       
  16.     if((listenfd = create_listen_fd()) == -1)  
  17.     {  
  18.         printf("create_listen_fd error/n");  
  19.         return -1;  
  20.     }  
  21.       
  22.     setnonblocking(listenfd);  
  23.     FD_ZERO(&rset);  
  24.     FD_SET(listenfd, &rset);  
  25.     FD_ZERO(&allset);  
  26.     allset = rset;  
  27.     iMax = listenfd;  
  28.       
  29.     for(;;)  
  30.     {  
  31.         rset = allset;  
  32.         nfds = select(iMax + 1, &rset, NULL, NULL, NULL);  
  33.         printf("up/n");  
  34.         if(FD_ISSET(listenfd, &rset))  
  35.         {  
  36.             connfd = accept(listenfd, NULL, NULL);  
  37.             setnonblocking(connfd);  
  38.             FD_SET(connfd, &allset);  
  39.             if(connfd > iMax)  
  40.                 iMax = connfd;  
  41.             for(int i = 0; i < HANDLE_CONNFD_COUNT; i++)  
  42.             {  
  43.                 if(connfdSet[i] < 0)  
  44.                     connfdSet[i] = connfd;  
  45.                 break;   
  46.             }  
  47.             if(--nfds == 0)  
  48.                 continue;  
  49.         }  
  50.         else  
  51.         {  
  52.             for(int i = 0; i < HANDLE_CONNFD_COUNT; i++)  
  53.             {  
  54.                 if(connfdSet[i] < 0)  
  55.                     continue;  
  56.                 if(FD_ISSET(connfdSet[i], &rset))  
  57.                 {  
  58.                     memset(buf, 0x00, sizeof(buf));  
  59.                     //read(connfdSet[i], buf, 100);  
  60.                     printf("read buf:%s/n", buf);  
  61.                     if(--nfds == 0)  
  62.                         break;  
  63.                 }  
  64.             }  
  65.         }  
  66.     }  
  67.     return 0;     
  68. }  


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