IO多路转接
2015-07-03 10:25
351 查看
IO多路转接的技术可以避免阻塞IO的弊端,因为我们有时候需要在多个描述符上读read、写write,如果使用阻塞IO,就有可能长时间阻塞在某个描述符上而影响其它描述符的使用。
关于阻塞IO的处理办法,可以考虑一下几个方案:
1、多进程。弊端是多个进程终止时的通信,增加了程序的复杂度。
2、多线程。弊端是多个线程之间的同步,同样也增加了程序的复杂度。
3、轮询polling。使用非阻塞IO读取数据,弊端是浪费CPU时间,在多任务系统中应当避免使用这种方法。
4、异步IO。用到了信号机制,如系统V的SIGPOLL信号,BSD的SIGIO信号,问题是并非所有系统都支持这种机制,而且这种信号对每个进程而言只有1个,如果使该信号对多个描述符都起作用,那么在接到此信号时进程无法判断是哪一个描述符已准备好可以进行IO。为了确定是哪一个,仍需将这几个描述符都设置为非阻塞的,并顺序试执行IO。
5、IO多路转接。这个是一种比较好的技术,它先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已准备好进行IO时,该函数才返回,在返回时,它告诉进程哪些描述符已准备好可以进行IO了。
poll、select、pselect这三个函数使我们能够执行IO多路转接。
下面介绍select函数——
传向select的参数告诉内核:我们所关心的描述符;对于每个描述符我们所关心的状态,读、写和异常;愿意等待多长时间。
从select返回时,内核告诉我们:已准备好的描述符数量;对于读、写或异常这三个状态中的一个,哪些描述符已准备好。使用这些返回信息,就可调用相应的IO函数,如read/write,并且确知该函数不会阻塞。返回值-1表示出错,返回值0表示没有描述符准备好,正返回值表示已经准备好的描述符,该值是三个描述符集中已准备好的描述符数之和。
select函数的第一个参数nfds取值为最大描述符加1,意思是在后面三个读、写、异常描述符集参数中找到最大描述符,然后加1。
select函数最后一个参数timeout的类型结构如下:
timeout为NULL时,等待。timeout的两个成员都为0时不等待。timeout的两个成员至少有一个不为0是等待指定的时间。
select函数的中间三个参数readfds、writefds、exceptfds是指向描述符集的指针,这三个描述符集说明了我们关心的可读、可写或处于异常条件的各个描述符,每个描述符集存放在一个fd_set数据结构中,为每一可能的描述符保持了一位。
对fd_set数据结构可以进行的处理是:分配一个这种类型的变量;将这种类型的一个变量值赋予同类型的另一个变量;或对于这种类型的变量使用下列四个函数中的一个。
调用FD_ZERO将一个指定的fd_set变量的所有位设置为0。调用FD_SET设置一个fd_set变量的指定位。调用FD_CLR则将一指定位清除。调用FD_ISSET测试一指定位是否设置。
下面举例select函数的用法:
关于阻塞IO的处理办法,可以考虑一下几个方案:
1、多进程。弊端是多个进程终止时的通信,增加了程序的复杂度。
2、多线程。弊端是多个线程之间的同步,同样也增加了程序的复杂度。
3、轮询polling。使用非阻塞IO读取数据,弊端是浪费CPU时间,在多任务系统中应当避免使用这种方法。
4、异步IO。用到了信号机制,如系统V的SIGPOLL信号,BSD的SIGIO信号,问题是并非所有系统都支持这种机制,而且这种信号对每个进程而言只有1个,如果使该信号对多个描述符都起作用,那么在接到此信号时进程无法判断是哪一个描述符已准备好可以进行IO。为了确定是哪一个,仍需将这几个描述符都设置为非阻塞的,并顺序试执行IO。
5、IO多路转接。这个是一种比较好的技术,它先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已准备好进行IO时,该函数才返回,在返回时,它告诉进程哪些描述符已准备好可以进行IO了。
poll、select、pselect这三个函数使我们能够执行IO多路转接。
#include <sys/select.h> int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask); #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout);
下面介绍select函数——
传向select的参数告诉内核:我们所关心的描述符;对于每个描述符我们所关心的状态,读、写和异常;愿意等待多长时间。
从select返回时,内核告诉我们:已准备好的描述符数量;对于读、写或异常这三个状态中的一个,哪些描述符已准备好。使用这些返回信息,就可调用相应的IO函数,如read/write,并且确知该函数不会阻塞。返回值-1表示出错,返回值0表示没有描述符准备好,正返回值表示已经准备好的描述符,该值是三个描述符集中已准备好的描述符数之和。
select函数的第一个参数nfds取值为最大描述符加1,意思是在后面三个读、写、异常描述符集参数中找到最大描述符,然后加1。
select函数最后一个参数timeout的类型结构如下:
struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */ };
timeout为NULL时,等待。timeout的两个成员都为0时不等待。timeout的两个成员至少有一个不为0是等待指定的时间。
select函数的中间三个参数readfds、writefds、exceptfds是指向描述符集的指针,这三个描述符集说明了我们关心的可读、可写或处于异常条件的各个描述符,每个描述符集存放在一个fd_set数据结构中,为每一可能的描述符保持了一位。
对fd_set数据结构可以进行的处理是:分配一个这种类型的变量;将这种类型的一个变量值赋予同类型的另一个变量;或对于这种类型的变量使用下列四个函数中的一个。
void FD_CLR(int fd, fd_set *set); int FD_ISSET(int fd, fd_set *set); void FD_SET(int fd, fd_set *set); void FD_ZERO(fd_set *set);
调用FD_ZERO将一个指定的fd_set变量的所有位设置为0。调用FD_SET设置一个fd_set变量的指定位。调用FD_CLR则将一指定位清除。调用FD_ISSET测试一指定位是否设置。
下面举例select函数的用法:
fd_set readset; fd_set writeset; FD_ZERO(&readset); FD_ZERO(&writeset); FD_SET(0, &readset); FD_SET(3, &readset); FD_SET(1, &writeset); FD_SET(2, &writeset); select(4, &readset, &writeset, NULL, NULL);
相关文章推荐
- jsp中页面之间的跳转forward与sendRedirect的区别
- ecshop设置一个子类对应多个父类并指定跳转url的修改方法
- 使用HTML5技术控制电脑或手机上的摄像头(转载)
- Extjs 复制对象
- GRE写作必备句型
- 《猜猜看游戏》第四天
- 双拼告捷,7月初.top域名注册总量破16.6万!
- hibernate之constrained详解
- SQL Server 2005 手动备份流程图
- opencv图像求差的绝对值cvAbsDiff和形态学开运算cvMorphologyEx
- oracle导入与导出出现示知命令或的解决方法
- Leetcode|Flatten Binary Tree to Linked List
- Mongodb异常关闭重启失败解决
- 简介Nginx中的location匹配规则
- js处理backspace和enter键
- PHP读取excel(6)
- 合并多个wav文件
- JS中navigator对象详解
- js数据类型判断和数组判断
- C++ Primer学习笔记(3)——神奇的容器vector及其迭代器iterator