select(),fd_set,FD_SET,FD_CLR,FD_ZERO,FD_ISSET的用法

 本文大致记录一下我对socket编程中的select()方法,类型fd_set以及FD_SET、FD_ZERO、FD_CLR、FD_ISSET这些宏的用法的了解,

有不当的地方,请指出。

1 select
在socket编程中,select的字面意思就是选择,也就是选择出那些可读或可写或出错的socket,其声明如下:

  1. int select(  
  2.   __in     int nfds,  
  3.   __inout  fd_set* readfds,  
  4.   __inout  fd_set* writefds,  
  5.   __inout  fd_set* exceptfds,  
  6.   __in     const struct timeval* timeout  
  7. );  

在Winsock和Berkeley socket中,第一个参数的意义不一样,Winsock中第一个参数被忽略掉,传0即可,Berkeley中,第一个参数要比
所有加入fd_set集合中的socket的值大,一般传递最大的socket值再加1.

select()方法一般用于非阻塞socket中,用于查询socket的状态,如上所述,查询socket是否可读或写或者出错。


2 fd_set
fd_set是一种类型,表示文件描述符的集合,socket编程中,可以理解为socket的集合,这种类型在select()方法的中间三个参数
中被用到,这三个参数分别表示可读socket集合、可写socket集合和出错socket集合。


3 FD_SET(fd, set)
Winsock中,FD_SET是一个宏定义,等价的方法描述如下,可以看出,FD_SET这个宏的作用就是把socket添加到一个fd_set类型的集合中。

  1. void FdSet(int fd, fd_set *set)  
  2. {  
  3.     do   
  4.     {  
  5.         u_int i;  
  6.         for (i = 0; i < ((fd_set *FAR)(set))->fd_count; i++)  
  7.         {  
  8.             if (((fd_set FAR *)(set))->fd_array[i] == (fd))  
  9.             {  
  10.                 break// 已经在集合里则不需要添加   
  11.             }  
  12.         }  
  13.         // 表示集合里还没有   
  14.         if (i == ((fd_set FAR*)(set))->fd_count)  
  15.         {  
  16.             if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE)  
  17.             {  
  18.                 ((fd_set FAR *)(set))->fd_array[i] = (fd);  
  19.                 ((fd_set FAR *)(set))->fd_count++;  
  20.             }  
  21.         }  
  22.     } while (false);  
  23. }  

4 FD_ZERO和FD_CLR
这两个宏分别表示将一个fd_set类型的集合清空以及从集合中删除某个socket。


5 FD_ISSET
判断某个socket是否在fd_set类型的集合中。Winsock中,这个宏的定义如下:

  1. #define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set FAR *)(set))  


那么,这几个类型及方法是如何关联使用的呢?关键在于select()方法。
在使用select方法前,可以先分别初始化几个fd_set类型变量,如下:

  1. fd_set readSet;  
  2. fd_set writeSet;  
然后将所要查询的socket放入这些集合中:
  1. FD_ZERO(&readSet);  // 先初始化   
  2. FD_ZERO(&writeSet);  
  3. FD_SET(m_socket, &readSet);  
  4. FD_SET(m_socket, &writeSet);  
这时候,m_socket这个socket已经同时存在于readSet和writeSet这两个集合中。
然后调用select()方法来查询readSet和writeSet中存储的所有socket的状态, 在select()执行完成后,此方法会清除readSet中
不可读的socket以及writeSet中清除不可写的socket,接着就可以调用FD_ISSET来判断m_socket是否还在readSet和writeSet中,如果不在,
则表示m_socket当前不可读也不可写,如果都在,则表示可读可写。最后就可以根据FD_ISSET的结果来做相应的处理。

至于select()方法的timeout参数,是用来设置select的超时时间的。

为了保险起见,在FD_ISSET调用成功后,再做如下判断:

  1. int iRet = 0;  
  2. int len = sizeof(iRet);  
  3. if (getsockopt(m_sock, SOL_SOCKET, SO_ERROR, (char*)&iRet, &len) == SOCKET_ERROR)  
  4. {  
  5.     return;  
  6. }  

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值