select、poll、epoll 比较

转载:http://blog.csdn.net/dodo_328/article/details/39081183

1.Selet:本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。

               缺点:1 单个进程可监视的fd数量被限制,因为受描述符集合fd_set限制,fd数量最大不超过1024;

                          2 需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大;

                          3 对socket进行扫描时是线性扫描;

                          4 Linux的实现中select返回时会将timeout修改为剩余时间,所以重复利用timeout需要注意。

函数原型:int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);

参数:nfds 需要监听的最大fd 值加1;

           readfds 等待从此集合中的文件描述符中到来的数据;

           writefds 等待向此集合中的文件描述符写入的数据;

           exceptfds 等待这些文件描述符操作的异常;

           timeout  超过此时间后函数返回。

返回值:-1  发生错误;

              0    超时;

             num   满足需求的文件描述符数目。

 

void FD_CLR(int fd,fd_set *set):用来从文件描述符集合中删除一个文件描述符。

void FD_ISSET(int fd, fd_set *set):用来测试在这个文件描述符集合中,此文件描述符是否被触发。

void FD_SET(int fd, fd_set *set):用来将一个文件描述符设置到文件描述符集合中去。

void FD_ZERO(fd_set *set):用来将文件描述符集合清零。

程序实例:

[objc] view plain copy
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<sys/time.h>  
  4. #include<sys/types.h>  
  5. #include<unistd.h>  
  6. #include<fcntl.h>  
  7.   
  8. #define oops(m,x){perror(m);exit(x);}  
  9. void showdata(charchar *,int );  
  10.   
  11. int main(int ac,charchar *av[])  
  12. {  
  13.     int fd1,fd2;  
  14.     int max_fd;  
  15.     fd_set readfds;  
  16.     struct timeval timeout;  
  17.     int retval;  
  18.       
  19.     if(ac != 4)  
  20.     {  
  21.         fprintf(stderr,"Usage:%s file1 file2 timeout\n",*av);  
  22.         exit(1);  
  23.     }  
  24.   
  25.     if((fd1 = open(av[1],O_RDONLY)) == -1)  
  26.         oops("file1 open",2);  
  27.   
  28.     if((fd2 = open(av[2],O_RDONLY)) == -1)  
  29.         oops("file2 open",3);  
  30.   
  31.     max_fd = 1 + ((fd1 > fd2)?fd1:fd2);  
  32.   
  33.     while(1)  
  34.     {  
  35.         FD_ZERO(&readfds);  
  36.         FD_SET(fd1,&readfds);  
  37.         FD_SET(fd2,&readfds);  
  38.   
  39.         timeout.tv_sec = atoi(av[3]);  
  40.         timeout.tv_usec = 0;  
  41.   
  42.         retval = select(max_fd,&readfds,NULL,NULL,&timeout);  
  43.   
  44.         if(retval == -1)  
  45.             oops("select",4);  
  46.         if(retval > 0)  
  47.         {  
  48.             if(FD_ISSET(fd1,&readfds))  
  49.                 showdata(av[1],fd1);  
  50.             if(FD_ISSET(fd2,&readfds))  
  51.                 showdata(av[2],fd2);  
  52.         }  
  53.         else  
  54.             printf("no input after %d seconds\n",atoi(av[3]));  
  55.     }  
  56. }  
  57.   
  58. void showdata(charchar *fname,int fd)  
  59. {  
  60.     char buf[BUFSIZ];  
  61.     int n;  
  62.   
  63.     printf("%s:",fname);  
  64.     fflush(stdout);  
  65.     n = read(fd,buf,BUFSIZ);  
  66.     if(n == -1)  
  67.         oops(fname,5);  
  68.     write(1,buf,n);  
  69.     write(1,"\n",1);  
  70. }  


 

2.Poll:它将用户传入的数组拷贝到内核空间,然后查阅每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有的fd没有发现设备就绪,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后,它又要再次遍历fd,这个过程经历了多次无谓的遍历。

          优点:没有最大链接数的限制,原因是因为它是基于链表来存储的;不会修改timeout的值。

          缺点:大量的fd数组被整体复制于用户态和内核地址空间之间。

          特点:“水平触发”:如果报告fd后,没有被处理,那么下次poll时会再次报告该fd。

struct pollfd{

       int fd;  //文件描述符

       short events;  //等待的事件

       short  revents; //实际发生的事件

}

函数原型:int poll(struct pollfd  fds[ ], nfds_t nfds,int timeout);

参数:fds[]  文件描述符以及等待的事件结构数组;

           nfds  表示监听的fds的长度;

           timeout 超时;

返回值:-1 发生错误;

              0   超时;

             num 满足需求的文件描述符总数。

events/revents:POLLIN|POLLOUT

程序实例:

[objc] view plain copy
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<unistd.h>  
  4. #include<poll.h>  
  5. #include<fcntl.h>  
  6.   
  7. #define oops(m,x){perror(m);exit(x);}  
  8.   
  9. void showdata(charchar *,int);   
  10.   
  11. int main(int ac,charchar *av[])  
  12. {  
  13.     int timeout,fd1,fd2;  
  14.     struct pollfd poll_array[2];  
  15.     //int i;  
  16.     int ret;  
  17.   
  18.     if(ac != 4)  
  19.     {  
  20.         fprintf(stderr,"Usage:%s file1 file2 timeout\n",*av);  
  21.         exit(1);  
  22.     }  
  23.   
  24.     timeout = atoi(av[3]);  
  25.   
  26.     if((fd1 = open(av[1],O_RDONLY)) == -1)  
  27.         oops(av[1],2);  
  28.     if((fd2 = open(av[2],O_RDONLY)) == -1)  
  29.         oops(av[2],3);  
  30.   
  31.     poll_array[0].fd = fd1;  
  32.     poll_array[0].events = POLLIN;  
  33.     poll_array[1].fd = fd2;  
  34.     poll_array[1].events = POLLIN;  
  35.   
  36.     while(1)  
  37.     {  
  38.         ret = poll(poll_array,2,timeout);  
  39.   
  40.         if(ret == -1)  
  41.             oops("poll error\n",1);  
  42.         if(ret == 0)  
  43.         {  
  44.             printf("timeout..\n");  
  45.             continue;  
  46.         }  
  47.   
  48.         if(poll_array[0].revents & POLLIN)  
  49.         {  
  50.             showdata(av[1],fd1);  
  51.         }  
  52.   
  53.         if(poll_array[1].revents &POLLIN)  
  54.             showdata(av[2],fd2);  
  55.     }  
  56.     return 0;  
  57. }  
  58.   
  59. void showdata(charchar *fname,int fd)  
  60. {  
  61.     char buf[BUFSIZ];  
  62.     int n;  
  63.   
  64.     printf("%s:",fname);  
  65.     fflush(stdout);  
  66.     n = read(fd,buf,BUFSIZ);  
  67.     printf("n:%d\n",n);  
  68.     if(n == -1)  
  69.         oops(fname,4);  
  70.     write(1,buf,n);  
  71.     write(1,"\n",1);  
  72. }  


 

3.Epoll:解决了select和poll的几个性能上的缺陷

            1. 不限制监听的描述符个数,只受进程打开的描述符总数的限制;

            2. 监听性能不随着监听描述符数的增加而增加,是0(1)的,不再是轮询描述符来探测事件,而是描述符主动上报事件;

            3.使用共享内存的方式,不在用户和内核之间反复传递监听的描述信息;

            4.返回参数就是触发事件的列表,不再遍历。

            注意:1.epoll创建了描述符,最后要close(epfd);

                       2.支持水平和边缘触发。

int epoll_creat(int size)

功能:用来创建epoll文件描述符。

参数:size 能在epoll上关注的最大fd数。

返回值:epfd。

int epoll_ctl(int epfd,int op,int fd, struct epoll_event *event)

功能:控制对指定的文件描述符执行op操作。

参数:epfd  epoll_creat()函数的返回值。

           op  EPOLL_CTL_ADD(增加)/EPOLL_CTL_DEL(删除)/EPOLL_CTL_MOD(修改)。

           fd   文件描述符。

           event  与fd 相关联的监听事件。

struct  epoll_event{

           _uint32_t  events;

           epoll_data_t  data;

};

events:EPOLLIN 可读。

            EPOLLOUT 可写。

            EPOLLRDHUP 套接口对端close或shutdown写,在ET(边缘)模式下比较有用。

            EPOLLET 边缘触发模式,在描述符状态跳变时才上报监听事件(监听默认是LT(水平)模式)。

            EPOLLPRI 紧急数据可读。

            EPOLLERR 异常事件。

            EPOLLHUP 挂起。 EPOLLERR 和EPOLLHUP始终由epoll_wait监听,不需要用户设置。

            EPOLLONESHOT  只一次有效,描述符在触发一次事件之后自动失效。fd还在继续监听,直到使用EPOLL_CTL_MOD重新激活,设置新的监听事件。

data: 是个共用体,可以存放和fd绑定的描述符信息。比如ip/port等。

typedef  union  epoll_data{

          void *ptr;//存放与fd绑定的信息。

          int fd;

          _uint32_t  u32;

          _uint32_t  u64;

}epoll_data_t;

int epoll_wait(int epfd,struct epoll_event *events,int maxevents, int timeout)

参数:epfd  epoll_creat()的返回值.

           events  用于回传待处理事件的数组,值结果参数。

           maxevents  每次能处理的事件数。

           timeout  超时设置。

返回值:-1  发生错误;

              0   超时;

             num  触发事件的描述符总数。

程序实例:

[objc] view plain copy
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<poll.h>  
  4. #include<unistd.h>  
  5. #include<fcntl.h>  
  6. #include<sys/types.h>  
  7. #include<sys/epoll.h>  
  8.   
  9. #define oops(m,x){perror(m);exit(x);}  
  10. #define MAX_SIZE_EVENT  500  
  11.   
  12. void showdata(int ,charchar *);  
  13.   
  14. int main(int ac ,charchar *av[])  
  15. {  
  16.     int fd1,fd2;  
  17.     int time;  
  18.     int epfd;  
  19.     struct epoll_event eventList[MAX_SIZE_EVENT];  
  20.     struct epoll_event fd1_event;  
  21.     struct epoll_event fd2_event;  
  22.     int ret;  
  23.     int n ;  
  24.       
  25.     if(ac != 4)  
  26.     {  
  27.         fprintf(stderr,"Usage:%s file1 file2 timeout\n",*av);  
  28.         exit(1);  
  29.     }  
  30.   
  31.     if((fd1 = open(av[1],O_RDONLY)) == -1)  
  32.         oops("file1 open",2);  
  33.     if((fd2 = open(av[2],O_RDONLY)) == -1)  
  34.         oops("file2 open",3);  
  35.       
  36.     time = atoi(av[3]);  
  37.   
  38.     epfd = epoll_create(MAX_SIZE_EVENT);  
  39.     fd1_event.events = EPOLLIN|EPOLLET;  
  40.     fd1_event.data.fd = fd1;  
  41.     fd1_event.data.ptr = av[1];  
  42.     fd2_event.events = EPOLLIN|EPOLLET;  
  43.     fd2_event.data.fd = fd2;  
  44.     fd2_event.data.ptr = av[2];  
  45.   
  46.     if(epoll_ctl(epfd,EPOLL_CTL_ADD,fd1,&fd1_event) < 0)  
  47.         oops("fd1_event epoll addfail",4);  
  48.     if(epoll_ctl(epfd,EPOLL_CTL_ADD,fd2,&fd2_event) < 0)  
  49.         oops("fd2_event epoll addfail",5);  
  50.   
  51.     while(1)  
  52.     {  
  53.         ret = epoll_wait(epfd,eventList,MAX_SIZE_EVENT,time);  
  54.         if(ret < 0)  
  55.             oops("epoll error",6);  
  56.         if(ret == 0)  
  57.         {  
  58.             printf("timeout\n");  
  59.         }  
  60.   
  61.         for(n = 0;n < ret; n++)  
  62.         {  
  63.             if(eventList[n].events & EPOLLERR || eventList[n].events & EPOLLHUP || !(eventList[n].events & EPOLLIN))  
  64.             {  
  65.                 printf("epoll error");  
  66.                 close(epfd);  
  67.                 close(eventList[n].data.fd);  
  68.                 return -1;  
  69.             }  
  70.             else if(eventList[n].events & EPOLLIN)  
  71.                 showdata(eventList[n].data.fd,eventList[n].data.ptr);  
  72.         }  
  73.   
  74.     }  
  75.     close(epfd);  
  76.     close(fd1);  
  77.     close(fd2);  
  78.     return 0;  
  79. }  
  80.   
  81. void showdata(int fd,charchar *fname)  
  82. {  
  83.     char buf[BUFSIZ];  
  84.     int n;  
  85.   
  86.     printf("%s:",fname);  
  87.     fflush(stdout);  
  88.   
  89.     n = read(fd,buf,BUFSIZ);  
  90.     if(n == -1)  
  91.         oops("fd read",6);  
  92.     write(1,buf,n);  
  93.     write(1,"\n",1);  
  94. }  


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384294.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C库函数 File

C库函数常用的有&#xff1a;fopen, fclose, fread, fwrite, fgets, fputs, fscanf, fprintf, fseek, fgetc, fputc, ftell, feof, flush等&#xff0c; 当使用fopen打开一个文件时通常返回一个文件指针 FILE *fp。FILE类型是一个结构体&#xff0c;包含文件描述符&#xff08;…

Unix 网络编程(四)- 典型TCP客服服务器程序开发实例及基本套接字API介绍

转载&#xff1a;http://blog.csdn.net/michael_kong_nju/article/details/43457393 写在开头&#xff1a; 在上一节中我们学习了一些基础的用来支持网络编程的API&#xff0c;包括“套接字的地址结构”、“字节排序函数”等。这些API几乎是所有的网络编程中都会使用的一些&…

C库函数与系统函数的关系

转载于:https://www.cnblogs.com/lr1402585172/p/10464933.html

Unix网络编程(六)高级I/O技术之复用技术 select

转载&#xff1a;http://blog.csdn.net/michael_kong_nju/article/details/44887411 I/O复用技术 本文将讨论网络编程中的高级I/O复用技术&#xff0c;将从下面几个方面进行展开&#xff1a; a. 什么是复用技术呢&#xff1f; b. 什么情况下需要使用复用技术呢&#xff1f; c. …

Ubuntu在vmware虚拟机无法上网的解决方法

http://blog.csdn.net/xueyushenzhou/article/details/50460183 在vmware中安装Ubuntu之后&#xff0c;我们希望基本的功能如上网、传输文件等功能都是可用的&#xff0c;但是经常遇到不能上网的情况。使用笔记本时&#xff0c;我们经常希望能通过无线网卡上网&#xff0c;但是…

IO 多路复用之poll总结

http://www.cnblogs.com/Anker/p/3261006.html IO多路复用之poll总结 1、基本知识 poll的机制与select类似&#xff0c;与select在本质上没有多大差别&#xff0c;管理多个描述符也是进行轮询&#xff0c;根据描述符的状态进行处理&#xff0c;但是poll没有最大文件描述符数量的…

C++项目中的extern C {}

http://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html 引言 在用C的项目源码中&#xff0c;经常会不可避免的会看到下面的代码&#xff1a; 123456789#ifdef __cplusplusextern "C" {#endif/*...*/#ifdef __cplusplus}#endif它到底有什么用呢&#xff0c;…

C语言实现单链表(带头结点)的基本操作(创建,头插法,尾插法,删除结点,打印链表)

http://blog.csdn.net/xiaofeige567/article/details/27484137 C语言实现单链表&#xff08;带头结点&#xff09;的基本操作&#xff08;创建&#xff0c;头插法&#xff0c;尾插法&#xff0c;删除结点&#xff0c;打印链表&#xff09; [plain] view plaincopy #include<…

单向循环链表C语言实现

http://blog.csdn.net/morixinguan/article/details/51771633 我们都知道&#xff0c;单向链表最后指向为NULL&#xff0c;也就是为空&#xff0c;那单向循环链表就是不指向为NULL了&#xff0c;指向头节点&#xff0c;所以下面这个程序运行结果就是&#xff0c;你将会看到遍历…

web服务器原理

什么是web服务器&#xff1f; 在Mosaic浏览器&#xff08;通常被认为是第一个图形化的web浏览器&#xff09;和超链接内容的初期&#xff0c;演变出了“web服务器”的新概念&#xff0c;它通过HTTP协议来提供静态页面内容和图片服务。在那个时候&#xff0c;大多数内容都是静态…

(C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作

http://blog.csdn.net/fisherwan/article/details/19760681 上午写了下单向循环链表的程序&#xff0c;今天下午我把双向链表的程序写完了。其实双向链表和单向链表也是有很多相似的地方的&#xff0c;听名字可以猜到&#xff0c;每个节点都包含两个指针&#xff0c;一个指针指…

(C++版)链表(一)——实现单向链表创建、插入、删除等相关操作

http://blog.csdn.net/fisherwan/article/details/25557545 前段时间用C语言实现了链表的相关操作&#xff0c;但是发现当时挺清楚的&#xff0c;过了一段时间又忘的差不多了&#xff0c;所以现在打算用C再实现一遍&#xff0c;由于初次用C实现&#xff0c;存在错误的地方还望大…

(C语言版)链表(二)——实现单向循环链表创建、插入、删除、释放内存等简单操作

http://blog.csdn.net/fisherwan/article/details/19754585 昨天写了单向链表的代码&#xff0c;今天上午把单向循环链表的程序给敲完了。链表的相关操作一样的&#xff0c;包含链表的创建、判断链表是否为空、计算链表长度、向链表中插入节点、从链表中删除节点、删除整个链表…

计科院首页静态网页

一.HTML代码 <!DOCTYPE html><html><head><meta charset"UTF-8"><title>首页</title> </head><body><div id"page"> <div id"page_head"> <div id"logo" aligncenter…

(C语言版)链表(四)——实现双向循环链表创建、插入、删除、释放内存等简单操作

http://blog.csdn.net/fisherwan/article/details/19801993 双向循环链表是基于双向链表的基础上实现的&#xff0c;和双向链表的操作差不多&#xff0c;唯一的区别就是它是个循环的链表&#xff0c;通过每个节点的两个指针把它们扣在一起组成一个环状。所以呢&#xff0c;每个…

(C语言版)链表(一)——实现单向链表创建、插入、删除等简单操作(包含个人理解说明及注释,新手跟着写代码)

http://blog.csdn.net/fisherwan/article/details/19701027 我学习了几天数据结构&#xff0c;今天下午自己写了一个单向链表的程序。我也是新手&#xff0c;所以刚开始学习数据结构的菜鸟们&#xff08;有大牛们能屈尊看一看&#xff0c;也是我的荣幸&#xff09;可以和我一起…

(C++版)链表(二)——实现单项循环链表创建、插入、删除等操作

http://blog.csdn.net/fisherwan/article/details/25561857 链表&#xff08;二&#xff09;单向循环链表的实现&#xff0c;下面实现代码&#xff1a; [cpp] view plaincopy <span style"font-size:18px;" deep"5">#include <iostream> #in…

(C++版)链表(三)——实现双向链表的创建、插入、删除等简单操作

http://blog.csdn.net/fisherwan/article/details/25649073 链表&#xff08;三&#xff09;实现双向链表操作&#xff0c;代码如下&#xff1a; [cpp] view plaincopy <span style"font-size:18px;" deep"5">#include <iostream> #include …

(C++版)链表(四)——实现双向循环链表创建、插入、删除等简单操作

http://blog.csdn.net/fisherwan/article/details/25649271 链表&#xff08;四&#xff09;实现双向循环链表简单操作&#xff0c;代码如下&#xff1a; [cpp] view plaincopy <span style"font-size:18px;" deep"5">#include <iostream> #…

双向链表的创建和相关操作

http://blog.csdn.net/jw903/article/details/38947753 双向链表其实是单链表的改进。 当我们对单链表进行操作时&#xff0c;有时你要对某个结点的直接前驱进行操作时&#xff0c;又必须从表头开始查找。这是由单链表结点的结构所限制的。因为单链表每个结点只有一个存储直接后…