select 和 epoll的编程实现区别(2)

来源:互联网 发布:linux压缩文件夹zip 编辑:程序博客网 时间:2024/05/19 02:44

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

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

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

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

共用代码

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

[cpp] view plaincopy
  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。创建监听句柄并打开监听

[cpp] view plaincopy
  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上。
[cpp] view plaincopy
  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会再次被唤醒。

[cpp] view plaincopy
  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. }  


<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(397) | 评论(0) | 转发(3) |
0

上一篇:select 和 epoll的编程实现区别

下一篇:linux非阻塞式socket编程之select()用法

相关热门文章
  • test123
  • 编写安全代码——小心有符号数...
  • 使用openssl api进行加密解密...
  • 一段自己打印自己的c程序...
  • sql relay的c++接口
  • linux dhcp peizhi roc
  • 关于Unix文件的软链接
  • 求教这个命令什么意思,我是新...
  • sed -e "/grep/d" 是什么意思...
  • 谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~