UNP学习第六章select 一、I/O复用典型的网络应用场合 二、I/O模型 三、select函数

  • 当客户处理多个描述字时,必须使用I/O复用,这在前一段中已做了描述。
  • 一个客户同时处理多个套接口时可能的,但很少出现。
  • 如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。
  • 如果一个服务器即要处理TCP,又要处理UDP。
  • 如果一个服务器要处理多个服务或者多个协议。

二、I/O模型

一个输入操作一般有两个不同的阶段:

1.等待数据准备好

2.从内核到进程拷贝数据

五个I/O模型基本区别:

  • 阻塞I/O

 UNP学习第六章select
一、I/O复用典型的网络应用场合
二、I/O模型
三、select函数

此系统调用直到数据报到达切拷贝到应用缓冲区或是出错才返回。

  • 非阻塞I/O模型

 UNP学习第六章select
一、I/O复用典型的网络应用场合
二、I/O模型
三、select函数

前三次调用recvfrom任无数据返回,因此内核立即返回一个EWOULDBLOCK错误。

第四次调用recvfrom时,数据已准备好,被拷贝到应用缓冲区,recvfrom返回成功指示。

一直调用recvfrom称之为轮询,这会对CPU时间极大浪费。

  • I/O复用模型

UNP学习第六章select
一、I/O复用典型的网络应用场合
二、I/O模型
三、select函数

调用select或poll,在这两个系统调用中的某一个上阻塞,而不是阻塞于真正的I/O系统调用。

我们阻塞select调用,等待数据报套接口可读。当select返回套接口可读条件时,我们调用recvfrom将数据报拷贝到应用缓冲区中。

这一种和第一种比较没有什么优越性,而且调用了两次系统调用。但是select可以等待多个描述字。

  • 信号驱动I/O模型

 我们也可以用信号,让内核描述字准备好时用信号SIGIO通知我们。

UNP学习第六章select
一、I/O复用典型的网络应用场合
二、I/O模型
三、select函数

先要允许套接口进行信号驱动I/O,并通过系统调用sigaction安装一个信号处理程序。

此系统调用立即返回,进程继续工作,它是非阻塞的。数据准备好被读时,就为该进程生成一个SIGIO信号。

我们可以在信号处理程序中调用recvfrom来读取数据报,并通知主循环来处理。(也可以通知主循环读取)

信号的好处是,不阻塞,主循环可以继续执行。

  • 异步I/O模型

 UNP学习第六章select
一、I/O复用典型的网络应用场合
二、I/O模型
三、select函数

和上一个信号驱动I/O由内核通知我们何时可以启动一个I/O操作,异步I/O是由内核通知我们I/O操作何时完成。

三、select函数

#include <sys/select.h>
#include <sys/time.h>

int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset
    const struct timeval *timeout);
返回:准备好描述字的正数目0超时,-1出错
maxfdp1:整数值,集合中所有文件描述符范围,所有文件描述符中的最大值+1
readset:指向一组等待可读性检查的套接口
writeset:指向一组等待可写性检查的套接口
exceptset:指向一组等待错误检查的套接口
timeout:select()最多等待时间,对阻塞操作则为NULL

timeout有三种可能:

1.永远等待下去:仅在有一个描述字准备好I/O时才返回,为此,我们将参数timeout设置为空指针

2.等待固定时间:再有一个描述字准备好I/O后返回,但不超过timeout

3.根本不等待:检查描述字后立即返回,这称为轮询。timeout指向0

 对于上面的fd_set数据类型,唯一可以进行处理的是:分配一个这种类型的变量,将这种类型的一个变量赋值给同类的另一个变量,或使用下面函数。

#include <sys/select.h>

int FD_ISSET(int fd, fd_set *fdset);  /*在调用select()函数后,用FD_ISSET来检测fd是否在set集合中,当检测到fd在set中则返回真,否则,返回假(0)*/
返回:若fd在描述符集中,返回非0值,否则返回0
void FD_CLR(int fd, fd_set *fdset);  /*将fd从set集合中清除*/
void FD_SET(int fd, fd_set *fdset);  /*将fd加入set集合*/
void FD_ZERO(fd_set *fdset);  /*将set清零使集合中不含任何fd*/

 相关的还有fd_set

typedef struct
{
/*XPG4.2requires this member name.Otherwise avoid the name
from the global name space.*/
#ifdef__USE_XOPEN
__fd_maskfds_bits[__FD_SETSIZE/__NFDBITS];
#define__FDS_BITS(set)((set)->fds_bits)
#else
__fd_mask__fds_bits[__FD_SETSIZE/__NFDBITS];
#define__FDS_BITS(set)((set)->__fds_bits)
#endif
}fd_set;