目录

IO多路复用

select系统调用

poll系统调用

Epoll *系统调用

Epoll vs select/poll

相关文章


Linux(实际上是Unix)的一个基本概念是Unix / Linux中的所有内容都是文件的规则。每个进程都有一个文件描述符表,该表指向文件,套接字,设备和其他操作系统对象。

与许多IO源一起使用的典型系统具有初始化阶段,然后进入某种待机模式–等待任何客户端发送请求并对其进行响应

一个简单的解决方案是为每个客户端创建一个线程(或进程),在读取之前阻止该线程,直到发送请求并写入响应为止。这对于少量客户端来说是可以的,但是如果我们想将其扩展到数百个客户端,则为每个客户端创建一个线程是一个坏主意

IO多路复用


解决方案是使用内核机制来轮询一组文件描述符。您可以在Linux中使用3个选项:

  • select(2)
  • poll(2)
  • epoll

以上所有方法都具有相同的思想,创建一组文件描述符,告诉内核您希望对每个文件描述符(读,写,..)做什么,并使用一个线程阻塞一个函数调用,直到至少一个文件描述符请求的操作可用

select系统调用


select()系统调用提供了一种用于实现同步多路复用I / O的机制

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

对select()的调用将一直阻塞,直到给定的文件描述符准备好执行I / O为止,或者直到经过可选的指定超时为止

监视的文件描述符分为三组

  • 监视readfds集中列出的文件描述符,以查看是否有数据可读取。
  • 监视writefds集中列出的文件描述符,以查看写操作是否将完成而不会阻塞。
  • 监视exceptionfds集中的文件描述符以查看是否发生异常,或者是否有带外数据可用(这些状态仅适用于套接字)。

给定的集合可以为NULL,在这种情况下,select()不会监视该事件。

成功返回后,将修改每个集合,以使其仅包含准备好由该集合描述的类型的I / O的文件描述符。

例:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <wait.h>
#include <signal.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>#define MAXBUF 256void child_process(void)
{sleep(2);char msg[MAXBUF];struct sockaddr_in addr = {0};int n, sockfd,num=1;srandom(getpid());/* Create socket and connect to server */sockfd = socket(AF_INET, SOCK_STREAM, 0);addr.sin_family = AF_INET;addr.sin_port = htons(2000);addr.sin_addr.s_addr = inet_addr("127.0.0.1");connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));printf("child {%d} connected \n", getpid());while(1){int sl = (random() % 10 ) +  1;num++;sleep(sl);sprintf (msg, "Test message %d from client %d", num, getpid());n = write(sockfd, msg, strlen(msg));    /* Send message */}}int main()
{char buffer[MAXBUF];int fds[5];struct sockaddr_in addr;struct sockaddr_in client;int addrlen, n,i,max=0;;int sockfd, commfd;fd_set rset;for(i=0;i<5;i++){if(fork() == 0){child_process();exit(0);}}sockfd = socket(AF_INET, SOCK_STREAM, 0);memset(&addr, 0, sizeof (addr));addr.sin_family = AF_INET;addr.sin_port = htons(2000);addr.sin_addr.s_addr = INADDR_ANY;bind(sockfd,(struct sockaddr*)&addr ,sizeof(addr));listen (sockfd, 5); for (i=0;i<5;i++) {memset(&client, 0, sizeof (client));addrlen = sizeof(client);fds[i] = accept(sockfd,(struct sockaddr*)&client, &addrlen);if(fds[i] > max)max = fds[i];}while(1){FD_ZERO(&rset);for (i = 0; i< 5; i++ ) {FD_SET(fds[i],&rset);}puts("round again");select(max+1, &rset, NULL, NULL, NULL);for(i=0;i<5;i++) {if (FD_ISSET(fds[i], &rset)){memset(buffer,0,MAXBUF);read(fds[i], buffer, MAXBUF);puts(buffer);}} }return 0;
}

我们从创建5个子进程开始,每个进程都连接到服务器并将消息发送到服务器。服务器进程使用accept(2)为每个客户端创建一个不同的文件描述符。select(2)中的第一个参数应该是三个集合中编号最高的文件描述符,加上1,因此我们检查了最大fd num

主无限循环创建一组所有文件描述符,调用选择并在返回时检查哪个文件描述符已准备好读取。为简单起见,我没有添加错误检查

返回时,select将集合更改为仅包含已准备好的文件描述符,因此我们需要在每次迭代时再次构建该集合。

我们需要告诉选择什么是编号最高的文件描述符,这是fd_set的内部实现。每个fd都用一位声明,因此fd_set是32个整数的数组(32 * 32bit = 1024位)。该功能检查任何位以查看其设置是否达到最大值。这意味着如果我们有5个文件描述符,但最大数目是900,则该函数将检查0到900之间的任何位以找到要观看的文件描述符。有一个posix替代选择– pselect,它在等待时添加信号掩码(请参见手册页)

选择–摘要:

  • 我们需要在每次通话之前建立每个集合
  • 该功能检查最高位数– O(n)的任何位
  • 我们需要遍历文件描述符以检查它是否存在于select返回的集合中
  • select的主要优点是它具有很高的可移植性-像OS一样的每个Unix都有它

poll系统调用


与select()不同的是,由于select()的三组基于位掩码的文件描述符效率不高,poll()采用了nfds pollfd结构的单个数组。原型更简单:

int poll (struct pollfd *fds, unsigned int nfds, int timeout);

pollfd结构的事件和返回事件具有不同的字段,因此我们不必每次都构建它:

struct pollfd {int fd;short events; short revents;
};

对于每个文件描述符,构建一个类型为pollfd的对象,并填充所需的事件。民意调查返回后,检查revents字段

要将上面的示例更改为使用poll:

  for (i=0;i<5;i++) {memset(&client, 0, sizeof (client));addrlen = sizeof(client);pollfds[i].fd = accept(sockfd,(struct sockaddr*)&client, &addrlen);pollfds[i].events = POLLIN;}sleep(1);while(1){puts("round again");poll(pollfds, 5, 50000);for(i=0;i<5;i++) {if (pollfds[i].revents & POLLIN){pollfds[i].revents = 0;memset(buffer,0,MAXBUF);read(pollfds[i].fd, buffer, MAXBUF);puts(buffer);}}}

就像我们对select所做的一样,我们需要检查每个pollfd对象以查看其文件描述符是否已准备就绪,但是我们不需要在每次迭代时都构建集合

投票与选择

  • poll()不需要用户计算编号最大的文件描述符的值+1
  • poll()对于大值文件描述符更有效。想象一下,通过select()观察值为900的单个文件描述符—内核将必须检查每个传入集合的每个位,直到第900位。
  • select()的文件描述符集是静态大小的。
  • 使用select(),文件描述符集将在返回时重建,因此每个后续调用都必须重新初始化它们。poll()系统调用将输入(事件字段)与输出(保留字段)分开,从而使阵列可以重复使用而无需更改。
  • select()的超时参数在返回时未定义。可移植代码需要重新初始化它。这不是pselect()的问题
  • 由于某些Unix系统不支持poll(),因此select()具有更高的可移植性。

Epoll *系统调用


在使用选择和轮询时,我们将管理用户空间中的所有内容,并在每次呼叫时发送设置以等待。要添加另一个套接字,我们需要将其添加到集合中,然后再次调用select / poll。

Epoll *系统调用可帮助我们在内核中创建和管理上下文。我们将任务分为3个步骤:

  • 使用epoll_create在内核中创建上下文
  • 使用epoll_ctl向/从上下文中添加和删除文件描述符
  • 使用epoll_wait等待上下文中的事件

让我们将上面的示例更改为使用epoll:

 struct epoll_event events[5];int epfd = epoll_create(10);......for (i=0;i<5;i++) {static struct epoll_event ev;memset(&client, 0, sizeof (client));addrlen = sizeof(client);ev.data.fd = accept(sockfd,(struct sockaddr*)&client, &addrlen);ev.events = EPOLLIN;epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev); }while(1){puts("round again");nfds = epoll_wait(epfd, events, 5, 10000);for(i=0;i<nfds;i++) {memset(buffer,0,MAXBUF);read(events[i].data.fd, buffer, MAXBUF);puts(buffer);}}

我们首先创建一个上下文(该参数将被忽略,但必须为正数)。当客户端连接时,我们创建一个epoll_event对象并将其添加到上下文中,并且在无限循环中,我们仅在上下文中等待。

Epoll vs select/poll


  • 我们可以在等待时添加和删除文件描述符
  • epoll_wait仅返回具有就绪文件描述符的对象
  • epoll具有更好的性能-O(1)代替O(n)
  • epoll可以表现为水平触发或边沿触发(请参见手册页)
  • epoll是特定于Linux的,因此不可移植

相关文章


《select用法》

《从select函数谈及系统调用原理》

《Linux Socket C语言网络编程:Select Socket》

《Linux Socket C语言网络编程:Poll Socket》

《Linux Socket C语言网络编程:Epoll Socket 》

《浅谈epoll》

《什么是epoll的水平触发与边缘触发?》

《linux-io-multiplexing-select-vs-poll-vs-epoll》

源代码:https://github.com/dev-area/Multiplexing-IO

或者:https://github.com/Rtoax/test/tree/master/c/Multiplexing-IO

Linux IO复用:select、poll、epoll的理解与对比相关推荐

  1. IO多路复用select,poll epoll以及区别

    看这个一次读懂 Select.Poll.Epoll IO复用技术 文章来简单理解下,如果不是很明白的话,可以参考下面转的知乎上面白话文列子 作者:Leslie 链接:https://www.zhihu ...

  2. IO模型(select, poll, epoll的区别和原理)

    参考<unix网络编程> 参考http://blog.csdn.net/blueboy2000/article/details/4485874 参考http://blog.csdn.net ...

  3. python3 异步 非阻塞 IO多路复用 select poll epoll 使用

    有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理还是有必要的. 下面记录下分别基于Select/Poll/Epoll的echo ser ...

  4. IO多路复用select/poll/epoll详解以及在Python中的应用

    IO multiplexing(IO多路复用) IO多路复用,有些地方称之为event driven IO(事件驱动IO). 它的好处在于单个进程可以处理多个网络IO请求.select/epoll这两 ...

  5. Python异步非阻塞IO多路复用Select/Poll/Epoll使用

    来源:http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理 ...

  6. linux网络编程--select/poll/epoll 详解

    目录 参考链接 epoll函数 close epoll event EL/LT ET Edge Trigger 边沿触发工作模式 LT Level Trigger 水平触发工作模式 epoll 源码解 ...

  7. Linux IO复用区别与epoll详解

    转载:http://blog.csdn.net/hacker00011000/article/details/52160590 一.select.poll.epoll之间的区别总结[整理]  sele ...

  8. python poll_python IO 多路复用 select poll epoll

    select select 原理 select 是通过系统调用来监视着一个由多个文件描述符(file descriptor)组成的数组,当select()返回后,数组中就绪的文件描述符会被内核修改标记 ...

  9. epoll编程实例客户端_深入底层探析网络编程之多路复用器(select,poll,epoll)

    IO模型 只关注IO,不关注IO读写完成后的事情. 同步:程序(APP)自己进行读/写操作 异步:由Kernel完成读/写,程序跑起来感觉像没有访问IO,访问的是buffer 阻塞:BLOCKING, ...

  10. 彻底搞懂 select/poll/epoll,就这篇了!

    之前已经把网络 I/O 相关要点都盘了,还剩 select/poll/epoll 这几个区别没说,这篇就来搞搞它们,并且是从完全理解原理的角度来区分它们. 本来是要上源码的,但是感觉没啥必要,身为应用 ...

最新文章

  1. 重装电脑后遇到的问题,其他设备,未知设备
  2. Centos中文输入法安装以及切换
  3. docker-compose 安装方法
  4. 面试时候可以问的问题集锦
  5. python输出数据到excel-python如何导出数据到excel文件
  6. 数据结构题:由逆置数组方法——逆置线性表L的所有元素
  7. 【MATLAB统计分析与应用100例】案例012:matlab读取Excel数据,调用robustfit函数作稳健回归
  8. JavaScript程序开发(十四)—函数声明与函数表达式
  9. centos7新机器需要安装的。。。。。。
  10. Java并发程序设计(二)Java并行程序基础
  11. php中嵌套html代码和html代码中嵌套php方式
  12. 四维的王坚和三维的阿里互联网汽车
  13. 简单理解盘索引地址的表示原理
  14. android获取sd的大小,Android实现获取SD卡总容量,可用大小,机身内存总容量及可用大小的方法...
  15. java 一级缓存,MyBatis一级缓存避坑完全指南
  16. Hive:动静态分区
  17. 谷歌浏览器用的是什么内核
  18. 一文2000字搞懂高并发性能指标:QPS、TPS、RT、并发数、吞吐量
  19. 好用的web报表设计器(报表工具)
  20. linux下隐藏文件 和 显示隐藏文件命令

热门文章

  1. dept在Java里面_EmpDeptManager 在JavaEE环境下搭建三大框架体系实现员工的增删改查系统 Develop 261万源代码下载- www.pudn.com...
  2. SpringBoot | 第十四章:基于Docker的简单部署
  3. Qt中文本编辑器实现语法高亮功能(Qscitinlla)
  4. 实习面试问题整理(一)
  5. [转]Mysql explain用法和性能分析
  6. Javascript综合应用小案例
  7. Multiple substitutions specified in non-positional format; did you mean to add the formatted=false
  8. Java SSM框架学习之Mybatis篇
  9. oracle rds 运维服务_RDS oracle数据库运维
  10. plsql如何显示表结构图_产品经理需了解的架构图/结构图知识