<网络编程>IO复用
IO复用是一种机制,一个进程可以监听多个描述符,一旦某个描述符就绪(读就绪和写就绪),能够同志程序进行相应的读写操作。
目前支持I/O复用的系统调用有select,poll,pselect,epoll,本质上这些I/O复用技术是同步I/O技术。在读写事件就绪后需要进程自己负责进行读写,即读写过程是进程阻塞的。
与多进程和多线程相比,I/O复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。
同步I/O操作导致请求进程阻塞,直到I/O操作完成。异步I/O不导致请求进程阻塞。
1、select:允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或者多个事件发生或者经历一段时间后才唤醒它。
#include <sys/select.h> #include <sys/time.h> int select(int maxfdpl, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);
- 参数
- maxfdpl:指定待测试的描述符个数,值为待测试的最大描述符加1
- readset:读描述符集合
- writeset:写描述符集合
- exceptset:异常描述符集合。
- timeout:内核等待任意描述符就绪的超时时间,超时函数返回0.永远等待下去,值为0;等待固定一段时间;立即返回。即timeval中的时间设置为0.
struct timeval{
long tv_sec;
long tv_usec;
};
- 描述集说明:
- select使用的描述符集,通常是一个整数数组,其中每个整数的一位对应一个描述符。
- 如果对三个描述符集中的某个不感兴趣,可以设置为空指针,如果都设置为空指针,会得到一个比sleep更加精确的定时器
<sys/select.h>中定义的FD_SETSIZE常值是数据类型fd_set中的描述符总数,其值通常是1024,不过很少用到这么多描述符,maxfdp1参数迫使我们计算
描述符就绪条件
- 套接字可读
- 该连接的读半部关闭,对这样的套接字读操作将不会阻塞并返回0
- 该套接字是一个监听套接字,且已完成的连接数不为0
- 套接字上有一个错误,对其读不会阻塞并返回-1,同时把errno设为确切错误条件。
- 该套接字接收缓存区中的数据字节数大于等于套接字接收缓冲区低水位标记的当前大小。
- 套接字可写
- 该套接字发送缓存区中的数据字节数大于等于套接字发送缓冲区低水位标记的当前大小。
- 该连接写半部关闭,对这样的套接字写将产生SIGPIPE信号
- 使用非阻塞式connect的套接字已建立连接,或者connect以失败告终
- 套接字上有一个错误,对其写将不会阻塞并返回-1,同时把errno设为确切错误条件
2、pselect
#include <sys/select.h> #include <sys/time.h> #include <signal.h> int select(int maxfdpl, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout, const sigset_t *signmask);
- 参数
maxfdp1:指定待测试的描述符个数,值为待测试的最大描述符加1(参数名的由来)readset:读描述符集writeset:写描述符集exceptset:异常描述符集。目前支持的异常条件只有两个timeout:(告知)内核等待任意描述符就绪的超时时间,超时函数返回0sigmask:该参数运行程序先禁止递交某些信号,再测试由这些当前被禁止信号的信号处理函数设置的全局变量,然后调用pselect,告诉它重新设置信号掩码- 相对于select的变化:
- 使用timespec结构,时间精度更高。
- 增加了第6个参数:一个指向信号掩码的指针。该参数运行程序先禁止递交某些信号,再测试由这些当前被禁止信号的信号处理函数设置的全局变量,然后调用pselect,告诉它重新设置信号掩码
3、poll
#include <poll.h> int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);
- 参数
fdarray:指向pollfd数组的指针,每个pollfd结构包含了描述符及其相应事件。
struct pollfd{
int fd; //监视的描述符
short events; //该描述符上监视的事件
short revents; //该描述符上发生的事件
};
- nfds:pollfd数组的元素个数(即监视的描述符总数.
- timeout:内核等待任意描述符就绪的超时时间,超时函数返回0.
INFTIM(一个负值):永远等待下去>0:等待一段固定时间0:立即返回(轮询)
如果不再关心某个特定描述符,可以把与之对应的pollfd结构的fd成员设置成一个负值。poll函数将忽略这样的pollfd结构的events成员,返回时将其revents成员的值置为0
4、epoll
#include <sys/epoll.h> int epoll_create(int size); int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event); int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);
- epoll_create():创建一个epoll句柄,它会占用一个fd,用完epoll后,必须将其关闭。
- 参数:
- size:告诉内核监听描述符的数量,并不是监听数量的最大值,是对内核初始分配内部数据结构的一个建议
- 返回值:创建的epoll句柄
- epoll_ctl():对描述符fd进行op操作。
- 参数:
epfd:epoll_create得到的epoll句柄。 - op:操作
- EPOLL_CTL_ADD:注册新的
fd到epfd中 - EPOLL_CTL_DEL:从
epfd中删除一个fd - EPOLL_CTL_MOD:修改已注册
fd的监听事件 - fd:操作的描述符
- event:告知内核需要监听的时间。
- EPOLLIN:对应的描述符可读
- EPOLLOUT:对应的描述符可写
- EPOLLPRI:对应的描述符有紧急数据可读(带外数据)
- EPOLLERR:对应的描述符发生错误
- EPOLLHUP:对应的描述符被挂断
- EPOLLET:将epoll设为边缘触发模式(默认为水平(LT)触发模式)
- EPOLLONESHOT:只监听一次事件,监听完后,如果需要再次监听,需再次将描述符加入到epoll队列
- epoll_wait():等待epoll句柄上的I/O事件,最多返回maxevents个事件
- 参数:
- epfd:epoll_create得到的epoll句柄。
- events:从内核得到事件的集合
- maxevents:返回事件的最大数量(不能大于创建epoll句柄时的size参数)
- timeout:超时参数
工作模式:
- LT水平触发模式:
- 应用程序可以不立即处理该事件。下次调用epoll_wait时,会再次向应用程序通知此事件
- 边缘触发(ET)模式
- 应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不再向应用程序通知此事件
select,poll,epoll比较
- 时间复杂度
- select--O(n):采取无差别轮询,找出能读的数据流以及写数据流
- poll--O(n):将用户传入的数组拷贝到内核空间,然后查询每个描述符状态,无最大连接限制
- epoll—O(1):哪个流发生了怎么样的I/O事件通知
优缺点:
- select
- 单个进程可监视的fd数量受限。
- 对socket的扫描是线性的,即采用轮询方式
- 需要维护一个用来存储大量fd的数组结构,使得用户空间和内核空间在传递该结构时,复制开销大
- poll
- 与select类似,将用户传入的数组拷贝到内核空间,然后查询每个fd的状态,如果设备就绪,则在设备等待队列中加入一次并继续遍历,若遍历完该数组没有发现就绪设备,则挂起该进程直到设备就绪或者主动超时。
- 没有最大连接限制(基于链表存储)
- 大量的fd数组被整体复制到用户态和内核态,而不管它们是否有意义
- 水平触发模式,如果这次报告的fd没有被处理,那么下次poll仍会报告
- epoll
- LT模式:只要fd可读,每次epoll_wait都会返回它的事件,提醒用户操作
- ET模式:只会提醒一次,除非有新数据流入,所以在ET模式下,读一个fd,一定要读光所有的buffer
- epoll使用事件的就绪通知方式,通过epoll_ctl注册fd,一旦fd就绪,内核就会采用类似于回调函数机制来激活fd。
- 无最大并发连接限制
- 效率提升(非轮询模式),只在意活跃的fd,而与连接总数无关。
- 内存拷贝利用mmap文件映射内存,加速与内核空间消息传递。
<网络编程>IO复用的更多相关文章
- Linux网络编程-IO复用技术
IO复用是Linux中的IO模型之一,IO复用就是进程预先告诉内核需要监视的IO条件,使得内核一旦发现进程指定的一个或多个IO条件就绪,就通过进程进程处理,从而不会在单个IO上阻塞了.Linux中,提 ...
- LINUX网络编程 IO 复用
参考<linux高性能服务器编程> LINUX下处理多个连接时候,仅仅使用多线程和原始socket函数,效率十分低下 于是就出现了selelct poll epoll等IO复用函数. 这 ...
- python 网络编程 IO多路复用之epoll
python网络编程——IO多路复用之epoll 1.内核EPOLL模型讲解 此部分参考http://blog.csdn.net/mango_song/article/details/4264 ...
- Socket网络编程-IO各种概念及多路复用
Socket网络编程-IO各种概念及多路复用 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.操作系统相关知识 1>.同步和异步 函数或方法被调用的时候,调用者是否得到最 ...
- python网络编程——IO多路复用之select
1 IO多路复用的概念 原生socket客户端在与服务端建立连接时,即服务端调用accept方法时是阻塞的,同时服务端和客户端在收发数据(调用recv.send.sendall)时也是阻塞的.原生so ...
- python网络编程——IO多路复用之epoll
1.内核EPOLL模型讲解 此部分参考http://blog.csdn.net/mango_song/article/details/42643971博文并整理 首先我们来定义流的概念,一个流 ...
- 健壮的网络编程IO函数-RIO包
RIO包 简介 Rio包即为Robust io函数包.包中函数是对Linux基本I/O函数的封装,使其更加健壮.高效,更适用于网络编程. 分析 Rio包由rio_t结构体和系列函数组成. 首先是两个不 ...
- 网络编程-----IO
IO模型介绍 阻塞IO 非阻塞 多路复用 异步 IO模型比较分析 selectors 阻塞IO:之前写的所有的socket,recv,accput都是 阻塞原理: 其实多数时间多用到了等待数据那里. ...
- Python网络编程-IO阻塞与非阻塞及多路复用
前言 问题:普通套接字实现的服务端的缺陷 一次只能服务一个客户端! accept阻塞! 在没有新的套接字来之前,不能处理已经建立连接的套接字的请求 re ...
随机推荐
- 如何用ABP框架快速完成项目(14) - 结尾? 当然不是, 这只是开始!
此文当前版本号: 3 最近更新时间: 2018-12-9 04:52 本课程是方向性课程, 目的是避免南辕北辙. 方向盘一旦打正确, 还得需要以下文章去写好具体程序: 前面每篇文章里面的链接, 比 ...
- matlab练习程序(神经网络分类)
注:这里的练习鉴于当时理解不完全,可能会有些错误,关于神经网络的实践可以参考我的这篇博文 这里的代码只是简单的练习,不涉及代码优化,也不涉及神经网络优化,所以我用了最能体现原理的方式来写的代码. 激活 ...
- PostgreSQL date_trunc() 和timestamp
timestamp 01.SELECT now()::timestamp + '1 year'; 02.SELECT now()::timestamp + '1 month'; 03.SELECT n ...
- Python MySQL事务、引擎、索引及第三方库sqlalchemy
本节内容 1.数据库介绍2.事务3.引擎4.索引5.ORM sqlalchemy 1.数据库介绍 什么是数据库? 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,每个数据库都有一 ...
- SQL2008无法附加数据库,提示“无法显示请求的对话框”(nColIndex实际值是-1)图文解决方法
SQL2008无法附加数据库,提示“无法显示请求的对话框”(nColIndex实际值是-1)图文解决方法 SQL2008无法附加数据库,提示“无法显示请求的对话框”(nColIndex实际值是-1)图 ...
- C#解析XML 例子二
<checkResult> <item> <fmId>XX0001</fmId> <fmItemId>20000RT</fmItemI ...
- 开发nginx启动脚本及开机自启管理(case)
往往我们在工作中需要自行写一些脚本来管理服务,一旦服务异常或宕机等问题,脚本无法自行管理,当然我们可以写定时任务或将需要管理的脚本加入自启等方法来避免这种尴尬的事情,case适用与写启动脚本,下面给大 ...
- python中的猴子补丁Monkey Patch
python中的猴子补丁Monkey Patch 什么是猴子补丁 the term monkey patch only refers to dynamic modifications of a cla ...
- Django中间件的使用
Django中间件的使用 中间件(middleware) 中间件应用于request与服务端之间和服务端与response之间,客户端发起请求到服务端接收可以通过中间件,服务端返回响应与客户端接收响应 ...
- CSS2属性选择器和css3选择器的用法和区别
兄弟们,这是我第一次写博客,希望对进来的人有用,写的不好别喷哈,谢谢. css2属性选择器: 1.[attribute] 例子: [title] 解释: 选择含有 title 属性的所有元 ...