C/C++ select fd_set解释

将套接口socket添加到fd_set 队列里面 后者可以通过传递给select函数来监听这一组套接口的状态,例如套接口上是否有数据传来等状态

select()机制中提供一fd_set的数据结构,实际上是一long类型的数组,每一个数组元素都能与一打开的文件句柄(不管是socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一socket或文件可读。 

typedef struct fd_set {
        u_int fd_count;               /* how many are SET? */
        SOCKET  fd_array[FD_SETSIZE];   /* an array of SOCKETs */
} fd_set;

很明了,一个计数的fd_count,另一个就是SOCKET数组。其中,FD_SETSIZE是64.(具体可以去查看vs的代码)

win下面FD_SET就是检查SOCKET在数组中是否存在,如果不存在,那么就插入到数组最后。而FD_CLR(fd,set)是把fd后面的东西往前拷贝,然后计数减1.FD_ZERO仅仅是把计数置为0(这个要注意!!)!FD_ISSET就看不到实现了。

简单函数使用 

fd_set set; 
FD_ZERO(&set); /*将set清零使集合中不含任何fd*/
FD_SET(fd,&set); /*将fd加入set集合*/ 
FD_CLR(fd,&set); /*将fd从set集合中清除*/ 
FD_ISSET(fd,&set); /*测试fd是否在set集合中*/
示例:
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
int main(void)
{
    fd_set fdset;
   
    FD_ZERO (&fdset);/*清空集合中所有的元素*/
  FD_SET(STDOUT_FILENO,&fdset);/*设置stdout,使集合中包含stdout*/
    if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)/*测试stdout是否包含在集合中*/
      printf("stdout has been set\n");
  else
      printf("stdout has not been set\n");
  FD_CLR(STDOUT_FILENO,&fdset);/*从位向量中清除stdout*、
  
    if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)
      printf("stdout has been set\n");/*再次测试*/
  else
      printf("stdout has not been set\n");

  return 0;
}

实例

uint32 SocketWait(TSocket *s,bool rd,bool wr,uint32 timems)    
{
     fd_set rfds,wfds;
#ifdef _WIN32
     TIMEVAL tv;
#else
     struct timeval tv;
#endif   /* _WIN32 */ 

     FD_ZERO(&rfds);
     FD_ZERO(&wfds); 

     if (rd)     //TRUE
          FD_SET(*s,&rfds);   //添加要测试的描述字 
     if (wr)     //FALSE
          FD_SET(*s,&wfds); 

     tv.tv_sec=timems/1000;     //second
     tv.tv_usec=timems%1000;     //ms 

     for (;;) //如果errno==EINTR,反复测试缓冲区的可读性
          switch(select((*s)+1,&rfds,&wfds,NULL,(timems==TIME_INFINITE?NULL:&tv)))  //测试在规定的时间内套接口接收缓冲区中是否有数据可读
         {                                              //0--超时,-1--出错
         case 0:     /* time out */
              return 0; 
         case (-1):    /* socket error */
              if (SocketError()==EINTR)
                   break;              
              return 0; //有错但不是EINTR 
          default:
              if (FD_ISSET(*s,&rfds)) //如果s是fds中的一员返回非0,否则返回0
                   return 1;

              if (FD_ISSET(*s,&wfds))
                   return 2;
              return 0;
         };
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐