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


    原文: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. }  


    阅读(397) | 评论(0) | 转发(3) |
    给主人留下些什么吧!~~
    评论热议
  • 相关阅读:
    【洛谷P4557】【JSOI2018】—战争(Minkowski Sum)
    【洛谷P4557】【JSOI2018】—战争(Minkowski Sum)
    【BZOJ3879】—SvT(后缀自动机+虚树/后缀自动机+单调栈)
    【BZOJ3879】—SvT(后缀自动机+虚树/后缀自动机+单调栈)
    多测师讲解pyhon__hashlib_高级讲师肖sir
    多测师讲解python函数 _open_高级讲师肖sir
    多测师讲解python函数 _zip_高级讲师肖sir
    多测师讲解内置函数 _format_高级讲师肖sir
    多测师讲解python _函数return_高级讲师肖sir
    多测师讲解python _函数中变量_高级讲师肖sir
  • 原文地址:https://www.cnblogs.com/black/p/5171660.html
Copyright © 2020-2023  润新知