Winsock I/O 方法 select

来源:互联网 发布:算法导论中文版pdf下载 编辑:程序博客网 时间:2024/05/22 20:39

select模型

        其使用select函数实现对I/O的管理。select函数可以判断套接字上是否有数据,或者是否能够向套接字上写数据。设计这可函数的目的是,为了防止套接字处于阻塞模式时,I/O调用过程处于阻塞模式;或者当套接字处于非阻塞模式时,产生WSAEWOULDBLOCK错误。如果不满足实现规定的参数条件,那么select函数在进行I/O操作时会阻塞。其定义如下:

[cpp] view plaincopyprint?
  1. int select( 
  2.    int nfds, 
  3.    fd_set FAR* readfds, 
  4.    fd_set FAR* writefds, 
  5.    fd_set FAR* exceptfds, 
  6.    const struct timeval FAR* timeout 
  7. ); 

 

  • nfds:这个参数会被忽略。
  • readfds:其为sd_set类型,其是一系列套接字的集合,用于检查可读性。这个集合要满足下面条件之一:1)有数据可读入  2)连接已经被关闭、重启或终止  3)假如已经调用listen,且有一个连接处于搁置状态,那么accept调用成功。
  • wrtiefds:用于检查可写性。其套接字要满足下面条件之一:1)有数据发出  2)如果正在对一个非阻塞连接调用进行处理,则连接就成功了。
  • exceptfds:用于带外数据。其套机字要满足下面条件之一:1)加入正在对一个非阻塞连接调用进行处理,连接尝试机会失败。  2)有00B数据可读操作。
  • timeout:其一个指向timeval结构体的指针,用于表示select函数在调用返回前的等待时间,如果为空指针({0,0}),表示无限期等待。不为0,表示其中至少一个套接字满足条件。
  • 返回值:如果select调用成功,会在fd_set结构中,返回被挂起的I/O操作的所有套接字句柄总量。超时,返回0。失败,返回SOCKET_ERROR。

select返回后,会对每个fd_set结构体进行修改,会将那些不存在被挂起I/O操作的套接字删除。也就是说,我们可以通过FD-ISSET宏来判断等待的套接字是还处于宏中。

timeval结构体定义如下:

[cpp] view plaincopyprint?
  1. struct timeval 
  2.    long tv_sec; 
  3.    long tv_usec; 
  4. }; 

 

  • tv_sec:以秒为单位指定等待时间。
  • tv_usec:以毫秒为单位指定等待时间。

在用select函数对套接字进行监听前,需要将套接字分配给一个集合。对fd_set集合进行处理与检查的宏:

  • FD_ZERO(*,set):将set集合初始化为空。
  • FD_CLR(s,* set):从set中删除套接字s.
  • FD_ISSET(s,* set):从集合set中检查s是否在其中;是,就返回TRUE。
  • FD_SET(s,* set):将套接字s加入集合set中。
  • FD_SETSIZE:对fd_set结构中的最多套接字进行设置。因为默认情况下最多能包含64个套接字。

下面是一个框架:

[cpp] view plaincopyprint?
  1. SOCKET s; 
  2. fd_set fread; 
  3. int ret; 
  4. while(TRUE) 
  5.     FD_SERO(&fread); 
  6.     FD_SET(s,&fread); 
  7.     if((ret=select(0,&fread,NULL,NULL,NULL))==SOCKET_ERROR) 
  8.     { 
  9.       .... 
  10.     } 
  11.     if(ret>0) 
  12.     { 
  13.        if(FD_ISSET(s,&fread)) 
  14.        { 
  15.        } 
  16.     } 

 

例如,假定我们想知道是否可从一个套接字中安全地读取数据,同时不会陷于无休止的“锁

定”状态,便可使用F D _ S E T宏,将自己的套接字分配给fd_read集合,再来调用select

。要想检测自己的套接字是否仍属fd_read集合的一部分,可使用FD_ISSET宏。采用下述步骤

,便可完成用select操作一个或多个套接字句柄的全过程:   
 1) 使用F D _ Z E R O宏,初始化自己感兴趣的每一个 f d _ s e t 。   
 2) 使用F D _ S E T宏,将套接字句柄分配给自己感兴趣的每个 f d _ s e t 。    
3)  调用s e l e c t函数,然后等待在指定的f d _ s e t集合中,I / O活动设置好一个或多个套接字句柄。 s e l e c t完成后,会返回在所有f d _ s e t集合中设置的套接字句柄总数,并对每个集合进行相应的更新。   
 4)  根据s e l e c t 的返回值,我们的应用程序便可判断出哪些套接字存在着尚未完成(待决) 的I / O操作—具体的方法是使用F D _ I S S E T宏,对每个f d _ s e t集合进行检查。   
 5)  知道了每个集合中“待决”的I / O操作之后,对I / O进行处理,然后返回步骤 1 )

,继续进 行s e l e c t处理。

      s e l e c t返回后,它会修改每个 f d _ s e t结构,删除那些不存在待决 I / O操作的套接字句柄。这正是我们在上述的步骤( 4 ) 中,为何要使用F D _ I S S E T宏来判断一个特定的套接字是否仍在集合中的原因。

 

 

0 0
原创粉丝点击