多路复用输入/输出——选择

  

<强>一,选择

,,,,系统提供选择函数来<强>实现多路复用输入/输出模型.select系统调用是用来让我们的程序<强> 强。程序会停在选择这里阻塞等待,直到被监视的文件句柄有一个或多个发生了状态改变。

,,,,文件句柄,其实就是一个整的数,我们最熟悉的句柄是0,1,2三个,0:标准输入,1:标准输出,2:标准错误输出0,1,2是整数表示的,对应的文件*结构:stdin、stdout, stderr。

<强>二,选择相关

<强> 1,选择函数,//一次可等待多个描述符

# include & lt; sys/select.h>

int选择(int nfds、fd_set * readfds fd_set * writefds,

,,,,,,,fd_set * exceptfds, struct timeval *超时);,

(1)参数:

//nfds:,需要监视的最大的文件描述符值+ 1,

//readfds:需要检测的可读文件描述符的集合。

//wtitefds:,需要检测的可写文件描述符的集合。

//exceptfds:,需要检测的异常文件描述符的集合。

//超时:结构timeval,用来设置select()的等待时间,

,,,//超时:

,,,,,,空:选择()没有超时,选择将一直被阻塞,直到某个文件描述符上发生了事件。

,,,,,,0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。

,,,,,,特定的时间值:如果在指定的时间段里没有事件发生,选择将返回。

(2)返回值:

,,,,执行成功则返回文件描述词状态已改变的个数。

,,,,如果返回0代表在描述词状态改变前已超过超时时间,没有返回;

,,,,当有错误发生时则返回1,错误原因存于errno,此时参数readfds, writefds, exceptfds和超时的值变成不可预测。

(3)选择“参数-值”传递的方式,同时,选择文件描述符有限定。

,,,,选择返回后,需要FD_ISSET轮询来获取就绪的描述符。

,,,,选择需要在返回后,通过遍历文件描述符来获取已经就绪的插座。

2,其他函数

,空白FD_CLR (int fd, fd_set *);//清除描述词组设置中相关fd的位

,int FD_ISSET (int fd, fd_set *);//测试描述词组设置中相关fd的位是否为真

,空白FD_SET (int fd, FD_SET *);//设置描述词组设置中相关fd的位

,空白FD_ZERO (fd_set *集);//清除描述词组集的全部位


# include & lt; aio.h>

int aio_read (struct aiocb * aiocbp);,,,,,,,与“轻轨。

3相关结构体

struct  timeval    {,,,,,long ,,, tv_sec;,,,,,,,,,/*, seconds  */,,   ,,,,,,long ,,, tv_usec;,,,,,,,,/*, microseconds  */};   和   struct  timespec    {,,,,,long ,,, tv_sec;,,,,,,,,,/*, seconds  */,   ,,,,,,long ,,, tv_nsec;,,,,,,,,/*, nanoseconds  */};

三、选择模型

1,选择模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每1位可以对应一个文件描述符fd,则1字节长的fd_set最大可以对应8个fd。

(1)执行fd_set设置;FD_ZERO(和集),则设置用位表示是0000年,0000年。

(2)若fd=5,执行FD_SET (fd,及设置);后设置变为0001,0000(第5位置为1)

(3)若再加入fd=2, fd=1,则设置变为0001,0011年

(4)执行选择(6,,,0,0,0)阻塞等待

(5)若fd=1, fd=2上都发生可读事件,则选择返回,此时设置变0000年为0011人。注意:没有事件发生的fd=5被清空。

2,特点:

(1)可监控的文件描述符个数取决与sizeof (FD_SET)的值。若服务器上sizeof (FD_SET)=512,每一点表示一个文件描述符,则服务器上支持的最大文件描述符是512 * 8=4096,虽然可调,但调整上限受于编译内核时的变量值。

(2)将fd加入选择监控集的同时,还要再使用一个数据结构数组保存放到选择监控集中的fd,一是用于再选择返回后,数组作为源数据和FD_SET进行FD_ISSET判断。二是选择返回后会把以前加入的但并无事件发生的fd清空,则每次开始选择前都要重新从数组取得fd逐一加入(FD_ZERO最先),扫描数组的同时取得fd最大值maxfd,用于选择的第一个参数。

(3)可见选择模型必须在选择前循环阵列(加fd,取maxfd),选择返回后循环阵列

(FD_ISSET判断是否有时间发生)。


四、选择服务器实例:

# include  & lt; stdio.h>   # include   # include   # include   # include   # include   # include   # include   # include   # include      # define  _BACKLOG_  5   int  fds [64];   void 使用(const  char  * proc)   {   printf (" % s (ip):(港口)\ n”, proc);   }   static  int 启动(const  char  * ip, const  int 端口)   {   int 袜子=插座(AF_INET SOCK_STREAM 0);//创建套接字   如果(sock  & lt;, 0)   {   perror(“套接字”);   退出(1);   }   struct  sockaddr_in 当地,//填充本地信息   local.sin_family=AF_INET;   local.sin_port=htons(港口);   local.sin_addr.s_addr=inet_addr (ip);      如果绑定(袜子,(struct  sockaddr *),当地,sizeof(本地),& lt;, 0),//绑定   {   perror(“绑定”);   出口(2);   }   如果(听(袜子,_BACKLOG_), & lt;, 0),//监听   {   perror(“听”);   出口(3);   }   return 袜子;,//返回套接字   }      int 主要(int 命令行参数个数,char  * argv [])   {   如果(argc  !=, 3)   {   使用(argv [0]);   return  1;   }   char  * ip=argv [1];   int 港口=atoi (argv [2]);   int  listen_sock=启动(ip、端口),,      struct  sockaddr_in 客户,,,//创建结构体sockaddr_in 客户端   socklen_t  len=sizeof(客户端);//取其长度   client.sin_family=AF_INET;   client.sin_port=htons(港口);   client.sin_addr.s_addr=inet_addr (ip);      int 做=0;   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null

多路复用输入/输出——选择