select、poll、epoll使用小结

转载:http://blog.csdn.net/kkxgx/article/details/7717125

Linux上可以使用不同的I/O模型,我们可以通过下图了解常用的I/O模型:同步和异步模型,以及阻塞和非阻塞模型,本文主要分析其中的异步阻塞模型。


一、select使用

这个模型中配置的是非阻塞I/O,然后使用阻塞select系统调用来确定一个I/O描述符何时有操作。使用select调用可以为多个描述符提供通知,对于每个提示符,我们可以请求描述符的可写,可读以及是否发生错误。异步阻塞I/O的系统流程如下图所示:


使用select常用的几个函数如下:

[cpp] view plaincopy
  1. FD_ZERO(int fd, fd_set* fds)   
  2. FD_SET(int fd, fd_set* fds)   
  3. FD_ISSET(int fd, fd_set* fds)   
  4. FD_CLR(int fd, fd_set* fds)   
  5. int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)   
fd_set类型可以简单的理解为按bit位标记句柄的队列。具体的置位、验证可以使用FD_SET,FD_ISSET等宏实现。在select函数中,readfds、writefds和exceptfds同时作为输入参数和输出参数,如果readfds标记了一个位置,则,select将检测到该标记位可读。timeout为设置的超时时间。

下面我们来看如何使用select:

[cpp] view plaincopy
  1. SOCKADDR_IN addrSrv;  
  2. int reuse = 1;  
  3. SOCKET sockSrv,connsock;  
  4. SOCKADDR_IN addrClient;  
  5. pool pool;  
  6. int len=sizeof(SOCKADDR);  
  7. /*创建TCP*/  
  8. sockSrv=socket(AF_INET,SOCK_STREAM,0);  
  9. /*地址、端口的绑定*/  
  10.   
  11. addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);  
  12. addrSrv.sin_family=AF_INET;  
  13. addrSrv.sin_port=htons(port);  
  14.   
  15. if(bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR))<0)  
  16. {  
  17.     fprintf(stderr,"Failed to bind");  
  18.     return ;  
  19. }  
  20.   
  21. if(listen(sockSrv,5)<0)  
  22. {  
  23.     fprintf(stderr,"Failed to listen socket");  
  24.     return ;  
  25. }  
  26. setsockopt(sockSrv,SOL_SOCKET,SO_REUSEADDR,(const char*)&reuse,sizeof(reuse));  
  27. init_pool(sockSrv,&pool);  
  28. while(1)  
  29. {  
  30.     /*通过selete设置为异步模式*/  
  31.     pool.ready_set=pool.read_set;  
  32.     pool.nready=select(pool.maxfd+1,&pool.ready_set,NULL,NULL,NULL);  
  33.     if(FD_ISSET(sockSrv,&pool.ready_set))  
  34.     {  
  35.         connsock=accept(sockSrv,(SOCKADDR *)&addrClient,&len);  
  36.         //loadDeal()/*连接处理*/  
  37.         //printf("test\n");  
  38.         add_client(connsock,&pool);//添加到连接池  
  39.     }  
  40.     /*检查是否有事件发生*/  
  41.     check_client(&pool);  
  42. }  
上面是一个服务器代码的关键部分,设置为异步的模式,然后接受到连接将其添加到连接池中。监听描述符上使用select,接受客户端的连接请求,在check_client函数中,遍历连接池中的描述符,检查是否有事件发生。





二、poll使用

poll函数类似于select,但是其调用形式不同。poll不是为每个条件构造一个描述符集,而是构造一个pollfd结构体数组,每个数组元素指定一个描述符标号及其所关心的条件。定义如下:

[cpp] view plaincopy
  1. #include <sys/poll.h>  
  2. int poll (struct pollfd *fds, unsigned int nfds, int timeout);  
  3. struct pollfd {  
  4. int fd; /* file descriptor */  
  5. short events; /* requested events to watch */  
  6. short revents; /* returned events witnessed */  
  7. };  

每个结构体的events域是由用户来设置,告诉内核我们关注的是什么,而revents域是返回时内核设置的,以说明对该描述符发生了什么事件。这点与select不同,select修改其参数以指示哪一个描述符准备好了。在《unix环境高级编程》中有一张events取值的表,如下:

POLLIN :可读除高优级外的数据,不阻塞

POLLRDNORM:可读普通数据,不阻塞

POLLRDBAND:可读O优先数据,不阻塞

POLLPRI:可读高优先数据,不阻塞

POLLOUT :可写普数据,不阻塞

POLLWRNORM:与POLLOUT相同

POLLWRBAND:写非0优先数据,不阻塞

其次revents还有下面取值

POLLERR :已出错

POLLHUP:已挂起,当以描述符被挂起后,就不能再写向该描述符,但是仍可以从该描述符读取到数据。

POLLNVAL:此描述符并不引用一打开文件

对poll函数,nfds表示fds中的元素数,timeout为超时设置,单位为毫秒若为0,表示不等待,为-1表示描述符中一个已经准备好或捕捉到一个信号返回,大于0表示描述符准备好,或超时返回。函数返回值返回值若为0,表示没有事件发生,-1表示错误,并设置errno,大于0表示有几个描述符有事件。

poll的使用和select基本类似。在此不再介绍。poll相对于是select的优势是监听的描述符数量没有限制。

三、epoll学习

epoll有两种模式,Edge Triggered(简称ET) 和 Level Triggered(简称LT).在采用这两种模式时要注意的是,如果采用ET模式,那么仅当状态发生变化时才会通知,而采用LT模式类似于原来的select/poll操作,只要还有没有处理的事件就会一直通知.

1)epoll数据结构介绍:

[cpp] view plaincopy
  1. typedef union epoll_data  
  2. {  
  3.   void        *ptr;  
  4.   int          fd;  
  5.   __uint32_t   u32;  
  6.   __uint64_t   u64;  
  7. } epoll_data_t;  
  8.   
  9. struct epoll_event  
  10. {  
  11.   __uint32_t   events; /* Epoll events */  
  12.   epoll_data_t data;   /* User data variable */  
  13. };  
常见的事件如下:

EPOLLIN:表示对描述符的可以读

EPOLLOUT:表示对描述符的可以写

EPOLLPRI:表示对描述符的有紧急数据可以读

EPOLLERR:发生错误

EPOLLHUP:挂起

EPOLLET:边缘触发

EPOLLONESHOT:一次性使用,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

2)函数介绍

epoll的三个函数

[cpp] view plaincopy
  1. int epoll_creae(int size);  
功能:该函数生成一个epoll专用的文件描述符

参数:size为epoll上能关注的最大描述符数

[cpp] view plaincopy
  1. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);  
功能:用于控制某个epoll文件描述符时间,可以注册、修改、删除

参数:epfd由epoll_create生成的epoll专用描述符

    op操作:EPOLL_CTL_ADD 注册   EPOLL_CTL_MOD修改  EPOLL_DEL删除

            fd:关联的文件描述符

    evnet告诉内核要监听什么事件

[cpp] view plaincopy
  1. int epoll_wait(int epfd,struct epoll_event*events,int maxevents,int timeout);  
功能:该函数等待i/o事件的发生。

参数:epfd要检测的句柄

     events:用于回传待处理时间的数组

     maxevents:告诉内核这个events有多大,不能超过之前的size

     timeout:为超时时间

使用方法参考:https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/epoll-example.c


epoll支持的FD上限是最大可以打开文件的数目(select面临这样的问题),IO效率不随FD数目增加而线性下降(select、poll面临的问题)使用mmap加速内核与用户空间的消息传递。现在libevent封装了几种的实现,可以通过使用libevent来实现多路复用。


 本文参考:https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/

   http://www.ibm.com/developerworks/cn/linux/l-cn-edntwk/index.html?ca=drs-

             http://www.ibm.com/developerworks/cn/linux/l-async/


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

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

相关文章

Qt报错:undefined reference to xxxxx

报错信息&#xff1a; 首先&#xff0c;要区分与undefined reference to xxxxx和 "xxxx was not declared in this scope"两种报错信息的差别&#xff0c;前者是因为编译器能找到函数的声明&#xff0c;但是找不到函数的定义&#xff0c;从而报错&#xff1b;而后者是…

对象的浅拷贝和深拷贝

对象的浅拷贝和深拷贝简要介绍代码实现简要介绍 浅拷贝&#xff1a;python拷贝一般都是浅拷贝。拷贝时&#xff0c;对象包含的子对象内容不拷贝。因此&#xff0c;源对象和拷贝对象引用同一个对象 深拷贝&#xff1a;使用copy模块的deepcopy函数&#xff0c;递归拷贝对象中包含…

用模板写单链表

转载自&#xff1a;http://blog.csdn.net/itcastcpp/article/details/39081953 为了加深对模板的理解&#xff0c;我们今天一起用模板写一个单链表&#xff0c;希望通过这个例子&#xff0c;能够帮助大家加深对模板的体会&#xff0c;具体如下&#xff1a; SList.hpp内容&#…

QT事件事件之一:Qt中的事件处理与传递

QT事件事件之一&#xff1a;Qt中的事件处理与传递前言一、简介二、QT中的事件三、事件的实现的方法前言 在QT中&#xff0c;事件是我们很常用的东西&#xff0c;以下是我用事件时总结和做法 一、简介 在QT中&#xff0c;事件作为一个对象&#xff0c;继承QEvent类&#xff0c…

linux下成功安装ffmpeg( 亲测有效 )

linux下成功安装ffmpeg&#xff08; 亲测有效 &#xff09;一、下载二、安装步骤1.安装yasm2.安装ffmpeg总结一、下载 ffmpeg 官网下载&#xff1a; http://ffmpeg.org/download.html 安装yasm 官网下载&#xff1a;http://yasm.tortall.net/Download.html 二、安装步骤 1.…

C++实现 简单 单链表

转自&#xff1a; http://blog.csdn.net/wonggonghong/article/details/21527577 我们首先建立一个<List.h>头文件&#xff0c;声明一个单链表结构&#xff1a; #include "List.h" [cpp] view plaincopy //创建一个单链表结构&#xff0c;包含一些常见的操作 …

ffmpeg音视频基础知识

ffmpeg音视频基础知识前言一、图像的基础知识二、视频编码基础知识1.视频和图片之间的关系2.为什么要编码&#xff1f;3.什么是编码&#xff1f;视频相关专业术语提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言…

Linux系统编程(一)

Linux系统编程&#xff08;一&#xff09;一、进程和程序二、内存布局内核空间用户空间三、进程状态四、环境变量五、进程共享一、进程和程序 程序&#xff1a;是指编译好的二进制文件&#xff0c;存储在磁盘中&#xff0c;不占用系统资源。 进程&#xff1a;是系统进行资源分…

Linux的SOCKET编程 简单演示

转载&#xff1a;http://blog.csdn.net/hguisu/article/details/7445768/ Linux的SOCKET编程详解 1. 网络中进程之间如何通信 进 程通信的概念最初来源于单机系统。由于每个进程都在自己的地址范围内运行&#xff0c;为保证两个相互通信的进 程之间既互不干扰又协调一致工作&a…

Unity(一)必然事件

【MonoBehaviour 类】&#xff08;一&#xff09;必然事件一、必然事件是什么&#xff1f;二、常用函数执行顺序1.Awake2.Start3.update4.FixedUpdate三、Awake和start区别一、必然事件是什么&#xff1f; 在Unity中必然事件也称脚本生命周期&#xff0c;是指在Unity脚本在唤醒…

Linux系统编程(二)孤儿进程和僵尸进程

Linux系统编程&#xff08;二&#xff09;一、exec函数族1.exec函数二、孤儿进程和僵尸进程三、wait和waitpid1.wait函数2.waitpid函数一、exec函数族 exec函数使用时&#xff0c;改程序的用户空间的代码和数据会被新程序给替代&#xff0c;会从新程序的启动例程开始。调用exe…

linux下c/c++实例之十socket简单应用

转自&#xff1a;http://blog.csdn.net/taiyang1987912/article/details/49738351 一、简介 通过socket扫描本机打开的tcp端口号&#xff0c;模拟用户名、密码登录服务器的过程、socket文件传输及模仿http服务器。 二、详解 1、Linux下tcp端口扫描 &#xff08;1&#xff09;…

Linux系统编程(三)进程间的通信

Linux系统编程&#xff08;三&#xff09;进程间的通信一、为什么需要进程之间的通信&#xff08;IPC&#xff09;&#xff1f;二、管道1.概念2.特质3.原理4.局限性5.代码2.读入数据三、共享存储映射注意事项父子进程通信一、为什么需要进程之间的通信&#xff08;IPC&#xff…

exec 函数族

转自&#xff1a;http://www.cnblogs.com/mickole/p/3187409.html linux系统编程之进程&#xff08;五&#xff09;&#xff1a;exec系列函数&#xff08;execl,execlp,execle,execv,execvp)使用 本节目标&#xff1a; exec替换进程映像exec关联函数组&#xff08;execl、execl…

Linux系统编程(四)信号

Linux系统编程&#xff08;四&#xff09;信号一、什么是信号&#xff1f;1、信号的本质2、信号来源硬件来源软件来源二、常见信号1.可靠信号和不可靠信号2、不可靠信号主要有以下问题:3、可靠信号与不可靠信号注册机制三、信号处理方式四、信号处理过程五、未决信号和阻塞信号…

SIGCHLD信号回收子进程

SIGCHLD信号回收子进程代码问题注意点代码 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <signal.h>void handler(int signo) {int status; pid_t pid;while ((pid waitpid(0, &status…

Wait waitpid

转自&#xff1a;http://www.cnblogs.com/mickole/p/3187770.html linux系统编程之进程&#xff08;六&#xff09;&#xff1a;父进程查询子进程的退出,wait,waitpid 本节目标&#xff1a; 僵进程SIGCHLDwaitwaitpid 一&#xff0c;僵尸进程 当一个子进程先于父进程结束运行时…

Linux C++ 简单爬虫

转载&#xff1a;http://blog.csdn.net/orthocenterchocolate/article/details/38665937 方便易用&#xff0c;传入URL&#xff0c;返回对应页面的内容 [cpp] view plaincopy #include <iostream> #include <string> #include <netdb.h> #include <…

Linux系统编程(七)消息队列

Linux系统编程&#xff08;七&#xff09;消息队列一、什么是消息队列二、消息队列内部原理三、实现消息队列的收发1.发送消息队列2.接收消息队列四、消息队列与命名管道的比较一、什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都…

基于Linux的SOCKET编程之TCP半双工Client-Server聊天程序

转自&#xff1a;http://blog.csdn.net/apollon_krj/article/details/53398448#0-tsina-1-64987-397232819ff9a47a7b7e80a40613cfe1 所谓半双工通信&#xff0c;即通信双方都可以实现接发数据&#xff0c;但是有一个限制&#xff1a;只能一方发一方收&#xff0c;之后交换收发对…