I/O多路转接

对于多个非阻塞I/O,怎么知道I/O何时已经处于可读或可写状态?

如果采用循环一直调用write/read,直到返回成功,这样的方式成为轮询(polling)。大多数时间I/O没有处于就绪状态,因此这样的轮询十分浪费CPU。

一种比较好的技术是使用I/O多路转接,也叫做I/O多路复用。其基本思想为:先构造一个有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已经准备好进行I/O时,该函数才返回。在返回时,它告诉进程哪些描述符已经准备好可以进行I/O了。

有3个函数poll、pselect、select可以使我们能够执行I/O多路转接。POSIX标准定义了select函数,poll是对该基本部分的XSI扩展。

select和pselect函数

select函数的参数告诉内核

1、我们所关心的描述符

2、对于每个描述符我们所关心的状态(是否读/写一个给定的描述符?是否关心一个描述符的异常状态?)

3、愿意等待多长时间(可以永远等待、等待一个固定时间、或不等待)

4、已经准备好描述符的状态

5、对于读、写或异常这三个状态中的每一个,哪些描述符已经准备好

当使用select的返回信息时,就可以调用相应的I/O函数(例如read或write),并且确知该函数不会阻塞。函数原型:

#include<sys/select.h>

int select(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds, struct timeval *restrict tvptr)

返回值:准备就绪的描述符数,若超时则返回0,若出错则返回-1

先看最后一个参数,它指定愿意等待的时间:

struct timeval{

long tv_sec;

long tv_usec;

};

当tvptr=NULL时,永远等待。如果捕捉到一个信号则中断此无限等待。

当tvptr->tv_sec=0且tvptr->tv_usec=0时,完全不等待。

当tvptr->tv_sec!=0或tvptr->tv_usec!=0时,等待相应时间。当指定描述符之一准备好时,或当指定时间已经超时,返回。

中间三个参数readfds、writefds、exceptfds指向描述符集的指针,是我们关心的可读、可写、处于异常条件的各个描述符。每个描述符集存放在fd_set数据类型中。这种数据类型为每一可能的描述符保持了一位,如图:

第一个参数maxfdp1的意思是最大描述符加1。在三个描述符集中找到最大描述符对应的数值加1。表示内核在此范围内寻找打开的位。

POSIX.1定义了一个select的变体pselect,原型如下:

int pselect(int maxfd1, fd_set *restrict readfds, fd_set *restrict writefds,

fd_set *restrict exceptfds, const struct timespec *restrict timeout,

const sigset_t *restrict sigmask)

和select有以下几点区别:

1、pselect超时值用的数据结构为timespec,更为准确

2、pselect超时值声明为const,保证了在pselect函数中不会改变

3、pselect可以指定一个信号屏蔽字,在调用时,以原子操作的方式安装该信号屏蔽字,在返回时恢复以前的信号屏蔽字。

poll函数

poll类似select函数,原型如下:

#include<poll.h>

int poll(struct pollfd fdarray[], nfds_t nfds, int timeout)

poll没有为每个状态(可读、可写、异常)构造一个描述符集,而是构造了一个pollfd结构体数组,每个数组指定一个描述符编号以及对其关心的状态。

struct pollfd {

int fd;         /* 文件描述符 */

short events;         /* 等待的事件 */

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

} ;

应该events事件设置成下表所表示的值,告诉内核我们关心的是什么。返回时,内核设置revents说明该描述符发生了什么。

最后一个参数说明愿意等待的时间。

时间: 2024-08-29 02:33:19

I/O多路转接的相关文章

I/O多路转接-epoll

By francis_hao    Aug 5,2017 APUE讲多路转接的章节介绍了select.pselect和poll函数.而epoll是linux内核在2.5.44引入的.在glibc 2.3.2添加了支持. epoll_create – 打开一个epoll文件描述符 epoll_ctl – 控制epoll文件描述符接口 epoll_wait – 在epoll文件描述符上等待一个I/O事件 概述 #include <sys/epoll.h>int epoll_create(int s

高性能服务器——I/O多路转接的三种模式(select &poll& epoll)

一.简单的服务器I/O模型 最简单的的TCP服务器,有三种模式: 1.单执行流,一个server端连接一个client端 2.多进程,一个server端通过多进程的方式,每个进程连接一个client端 3.多线程,一个server端通过多进程的方式,每个线程连接一个client端 (http://zhweizhi.blog.51cto.com/10800691/1830267) 这里实现过 要提升服务器性能,其实就是想要让一个server端能在负载允许的情况下,连接尽可能多的client端. 因

IO多路转接

IO多路转接的技术可以避免阻塞IO的弊端,因为我们有时候需要在多个描述符上读read.写write,如果使用阻塞IO,就有可能长时间阻塞在某个描述符上而影响其它描述符的使用. 关于阻塞IO的处理办法,可以考虑一下几个方案: 1.多进程.弊端是多个进程终止时的通信,增加了程序的复杂度. 2.多线程.弊端是多个线程之间的同步,同样也增加了程序的复杂度. 3.轮询polling.使用非阻塞IO读取数据,弊端是浪费CPU时间,在多任务系统中应当避免使用这种方法. 4.异步IO.用到了信号机制,如系统V的

【Nginx】I/O多路转接之select、poll、epoll

从socket中读取数据可以使用如下的代码: while( (n = read(socketfd, buf, BUFSIZE) ) >0) if( write(STDOUT_FILENO, buf, n) = n) { printf(“write error”); exit(1); } 当代码中的socketfd描述符所对应的文件表项是处于阻塞时,它会一直阻塞,直到有数据从网络的另一端发送过来.如果它是一个服务器程序,它要读写大量的socket,那么在某一个socket上的阻塞很明显会影响与其它

select函数与I/O多路转接

相作大家都写过读写IO操作的代码,例如从socket中读取数据可以使用如下的代码: while( (n = read(socketfd, buf, BUFSIZE) ) >0) if( write(STDOUT_FILENO, buf, n) = n) { printf("write error"); exit(1); } 当代码中的socketfd描述符所对应的文件表项是处于阻塞时,它会一直阻塞,直到有数据从网络的另一端发送过来.如果它是一个服务器程序,它要读写大量的socke

I/O多路转接select/poll/epoll

I/O多路转接(多路复用)又被称为“事件驱动”,是操作系统提供的一个功能,当你关心的文件(如socket)可读.可写时(称为事件就绪)采用某种方式通知你,只有收到通知时你才去执行read/write操作,这样在每次读或写时就不会阻塞,即I/O操作中等的部分交给操作系统内核去完成,而read/write之类的操作只需要在事件就绪时完成数据拷贝.等的过程由select/poll/epoll等系统调用触发,这些函数可同时监视多个描述符上的事件是否就绪,因此可以在一个线程内不发生阻塞的交替完成多个文件的

I/O多路转接 &#160; ---- &#160; poll

一.poll poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多. 二.poll相关函数 #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); //fds: pollfd结构体 events: 要监视的事件 revents: 已经发生的事件,  设置标志 来反映相关条件的存在 常量            

I/O多路转接之select——基于TCP协议

关于select的基础知识 a. select是系统提供的多路复用输入输出模型.它是用来监视多个文件句柄的状态变化. b. 程序会停在select等,直到被监视的文件句柄至少有一个发生了状态改变. c. 文件句柄是整数 函数 a. 参数 nfds:需要监视的最大文件描述符值加1: struct timeval结构用于描述一段时间长度,若超出这个时间,需要监视的描述符没有发生,则返回0. 3.代码实现  21     //  22     int sock=socket(AF_INET,SOCK_

I/O多路转接之poll

不同与select使用三个位图来表示三个fdset的方式,poll使用一个 pollfd的指针实现. pollfd结构包含了要监视的event和发生的event,不再使用select"参数-值"传递的方式.同时,pollfd并没有最大数量限制(但是数量过大后性能也是会下降). 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符. 从上面看,select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的socket.事 实上,同时连接的大量客户端在一