linux—I/O多路转接之select

【I/O多路转接】
socket中读取数据可以使用如下的代码:

while( (n = read(socketfd, buf, BUFSIZE) ) >0)

if( write(STDOUT_FILENO, buf, n) = n)

{

printf(“write error”);

exit(1);

}

当代码中的socketfd描述符所对应的文件表项是处于阻塞时,它会一直阻塞,直到有数据从网络的另一端发送过来。如果它是一个服务器程序,它要读写大量的socket,那么在某一个socket上的阻塞很明显会影响与其它socket的交互过程。类似的问题不单单出现在网络上,还可以出现在读写加锁的文件和FIFO等等一系列的情况。

一种比较好的解决方法似乎是采用非阻塞IO来实现。把所要读取数据的socketfd设置为非阻塞状态,依次用read函数检查是否有数据到来,如有,它会返回接到数据的个数,否则它会返回-1以表示当前还没有数据到达。这样,对于每个socket,如有数据到来则读取,没有也会马上返回。这就是非阻塞IO的好处拉。部分代码如下:

//clientfd[]为客户端的socket描述符组数,假设数组的大小为MAX,并且所有客户端socket描述符都设置为非阻塞状态时。

for(i = 0; i < MAX; ++i)

{

int n;

if( (n = read(clientfd[i], buf, SZIE)) >0)

{

//send response to client in here.

}

}

这里代码看起来与上面的代码没有太大的区别,其实是有很大的区别;区别就是使使用了非阻塞IO进行整个交互过程,使得各个客户端都得到相对平等的时间待遇。这种模式我们通常称为这“轮询”模式。轮询模式同样有它的不足之处,在执行read函数时,实际上大部分时间还是没有数据可读的,但仍不断地执行read,浪费了很多CPU时间。


       I/O多路转接(I/O multiplexing)就可以解决上述的问题。它可谓是上面两种方法的接衷:先构造一张有关描述符的数据表,然后调用一个函数,仅当有一个或多个描述符已准备可以进行IO操作时才返回,否则一直阻塞。在返回时,它会告诉进程那些描述符已准备好可以进行IO

【select函数】

函数的功能:实现多路转接,通过调用内核来实现。它向内核提供如下的参数

1)我们所关心的描述符

2)对于每个描述符,我们所关心的条件(是否读一个给定的描述符,还是想写一个给定的描述符,还是关心一个描述符的异常条件)

3)希望等待多久时间(可以永远等待,等待一个固定时间,或完全不等待)

select返回时,内核告诉我们:

1)已准备好的描述符数量

2)哪一个描述符已准备好读、写或异常条件

使用这种返回值,就可调用相应的I/O函数,通常是readwrite,并确知该函数不会阻塞。

【编写select】
linux—I/O多路转接之select
linux—I/O多路转接之select
linux—I/O多路转接之select
linux—I/O多路转接之select
linux—I/O多路转接之select
linux—I/O多路转接之select
linux—I/O多路转接之select
linux—I/O多路转接之select
linux—I/O多路转接之select

【代码结果】
linux—I/O多路转接之select