select函数(一)

来源:互联网 发布:acr122u破解软件 下载 编辑:程序博客网 时间:2024/05/16 14:53

select函数使我们在SVR4和4.3+BSD之下可以执行I/O多路转接,传向select的参数告诉内核:(1) 我们所关心的描述符。(2) 对于每个描述符我们所关心的条件(是否读一个给定的描述符?是否想写一个给定的描述符?是否关心一个描述符的异常条件?)。(3) 希望等待多长时间(可以永远等待,等待一个固定量时间,或完全不等待)。

  对select指定读、写和异常条件描述符对 fg_set 数据类型可以进行的处理是: ( a )分配一个这种类型的变量, ( b )将这种类型的一个变量赋与同类型的另一个变量,( c )对于这种类型的变量使用下列四个宏:以下列方式说明了一个描述符集后:fd_set rset;int fd;必须用FDZERO清除其所有位:FD_ZERO (&rset);然后在其中设置我们关心的各位:FD_SET (fd,&rset);FD_SET (STDIN_FILENO,&rset);从select返回时,用FDISSET测试该集中的一个给定位是否仍旧设置:if (FD_ISSET(fd, &rset)){. . .}select 中间三个参数中的任意一个(或全部)可以是空指针,这表示对相应条件并不关心。如果所有三个指针都是空指针,则 select 提供了较 sleep 更精确的计时器(s l e e p等待整数秒,而对于s e l e c t,其等待的时间可以小于1秒;其实际分辨率取决于系统时钟。)selcet 第一个参数 maxfdp1 的意思是“最大f d加1(max fd plus 1)”。在三个描述符集中找出最高描述符编号值,然后加1,这就是第一个参数值。也可将第一个参数设置为FDSETSIZE,这是一个< s y s / t y p e s . h >中的常数,它说明了最大的描述符数(经常是2 5 6或1 0 2 4)。但是对大多数应用程序而言,此值太大了。确实,大多数应用程序只应用3 ~ 1 0个描述符。如果将第三个参数设置为最高描述符编号值加1,内核就只需在此范围内寻找打开的位,而不必在数百位的大范围内搜索。例如,若编写下列代码:fd_set readset, writeset;FDZERO ( &readset ) ;FDZERO ( &writeset ) ;FD_SET(0, &readset);FD_SET(3, &readset);FD_SET(1, &writeset);FD_SET(2, &writeset);select (4, &readset, &writeset, NULL, NULL);然后,图1 2 - 1 0显示了这两个描述符集的情况。 因为描述符编号从0开始,所以要在最大描述符编号值上加1。第一个参数实际上是要检查的描述符数(从描述符0开始)。select有三个可能的返回值。(1) 返回值-1表示出错。这是可能发生的,例如在所指定的描述符都没有准备好时捕捉到一个信号。(2) 返回值0表示没有描述符准备好。若指定的描述符都没有准备好,而且指定的时间已经超过,则发生这种情况。(3) 返回一个正值说明了已经准备好的描述符数,在这种情况下,三个描述符集中仍旧打开的位是对应于已准备好的描述符位。注意,除非返回正值,否则在返回后检查描述符集是没有意义的。若捕捉到信号或计时器超时,那么描述符集的值取决于实现。确实,若计时器超时,4 . 3 + B S D并不改变描述符集,而S V R 4则清除描述符集。在S V R 4和B S D的s e l e c t实现之间,有另一些差异。B S D系统总是返回每一个集中准备就绪的描述符数之和。若两个集中的同一描述符准备就绪(例如,读集和写集),则该描述符计两次。不幸, S V R 4更改了这一点,若同一描述符在多个集中准备就绪,该描述符只计一次。这再一次显示了我们将会碰到的问题,直至P O S I X标准化了s e l e c t这样的函数才能解决此问题。对于“准备好”的意思要作一些更具体的说明:(1) 若对读集(re a d f d s)中的一个描述符的read不会阻塞,则此描述符是准备好的。(2) 若对写集(w r i t e f d s)中的一个描述符的write不会阻塞,则此描述符是准备好的。(3) 若对异常条件集( e x c e p t f d s)中的一个描述符有一个未决异常条件,则此描述符是准备好的。现在,异常条件包括: ( a )在网络连接上到达指定波特率外的数据,或者( b )在处于数据包方式的伪终端上发生了某些条件。(S t e v e n s〔1 9 9 0〕的1 5 . 1 0节中说明了这种条件。)应当理解一个描述符阻塞与否并不影响s e l e c t是否阻塞。也就是说,如果希望读一个非阻塞描述符,并且以超时值为5秒调用s e l e c t,则s e l e c t最多阻塞5秒。相类似,如果指定一个无限的超时值,则s e l e c t阻塞到对该描述符数据准备好,或捕捉到一个信号。如果在一个描述符上碰到了文件结束,则s e l e c t认为该描述符是可读的。然后调用r e a d,它返回0,这是U N I X指示到达文件结尾处的方法。(很多人错误地认为,当到达文件结尾处时,s e l e c t会指示一个异常条件。) 

从select返回时,内核告诉我们:(1) 已准备好的描述符的数量。(2) 哪一个描述符已准备好读、写或异常条件。使用这种返回值,就可调用相应的I / O函数(一般是r e a d或w r i t e),并且确知该函数不会阻塞。#include <sys/types.h>/* fd_set data type */#include <sys/time.h> /* struct timeval */#include <unistd.h> /* function prototype might be here */int select (int maxfd1, fd_set  *readfd, fd_set  *writefds, fd_set  *exceptfds, struct timeval  *tvptr) ;返回:准备就绪的描述符数,若超时则为0,若出错则为- 1先说明最后一个参数,它指定愿意等待的时间。struct timeval{long tv_sec; /* seconds */long tv_usec; /* and microseconds */};有三种情况:*tvptr= =NULL永远等待。如果捕捉到一个信号则中断此无限期等待。当所指定的描述符中的一个已准备好或捕捉到一个信号则返回。如果捕捉到一个信号,则s e l e c t返回-1, e r r n o设置为E I N T R。*tvptr->tvsec==0 && tvptr->tvusec==0完全不等待。测试所有指定的描述符并立即返回。这是得到多个描述符的状态而不阻塞select函数的轮询方法。*tvptr->tvsec!=0 || tvptr->tvusec!=0等待指定的秒数和微秒数。当指定的描述符之一已准备好,或当指定的时间值已经超过时立即返回。如果在超时时还没有一个描述符准备好,则返回值是0,(如果系统不提供微秒分辨率,则tvptr->tvusec值取整到最近的支持值。)与第一种情况一样,这种等待可被捕捉到的信号中断。中间三个参数 readfds、writefds 和 exceptfds 是指向描述符集的指针。这三个描述符集说明了我们关心的可读、可写或处于异常条件的各个描述符。每个描述符集存放在一个f d s e t数据类型中。这种数据类型的实现可见图12-9,它为每一可能的描述符保持了一位。


原创粉丝点击