摘自:www.cctry.com
选择模型select
int select(
__in int nfds, 参数nfds会被忽略。之所以仍然要提供这个参数,只是为了保持与Berkeley套接字兼容。
__in_out fd_set* readfds, 用于检查可读性
__in_out fd_set* writefds, 用于检查可写性
__in_out fd_set* exceptfds, 用于检查例外数据
__in const struct timeval* timeout 时间结构
);
fd_set 结构是一组套接字的集合
fdset 代表着一系列特定套接字的集合。其中, readfds 集合包括符合下述任何一个条件的套接字:
● 有数据可以读入。
● 连接已经关闭、重设或中止。
● 假如已调用了listen,而且一个连接正在建立,那么accept函数调用会成功。
writefds 集合包括符合下述任何一个条件的套接字:
● 有数据可以发出。
● 如果已完成了对一个非锁定连接调用的处理,连接就会成功。
exceptfds 集合包括符合下述任何一个条件的套接字:
● 假如已完成了对一个非锁定连接调用的处理,连接尝试就会失败。
● 有带外(Out-of-band,OOB)数据可供读取。
Winsock 提供了下列宏操作,可用来针对 I/O活动,对 fdset 进行处理与检查:
● FD_CLR(s, *set):从set中删除套接字s。
● FD_ISSET(s, *set):检查s是否set集合的一名成员;如答案是肯定的是,则返回TRUE。
● FD_SET(s, *set):将套接字s加入集合set。
● FD_ZERO( * set):将set初始化成空集合。
大致过程:
1) 使用FDZERO宏,初始化一个fdset对象;
2) 使用FDSET宏,将套接字句柄加入到fdset集合中;
3) 调用 select 函数,等待其返回……select 完成后,会返回在所有 fdset 集合中设置的套接字句柄总数,
并对每个集合进行相应的更新。
4) 根据 select的返回值和 FDISSET宏,对 fdset 集合进行检查。
5) 知道了每个集合中“待决”的 I/O操作之后,对 I/O进行处理,
然后返回步骤1 ),继续进行 select 处理。
示例代码:
BOOL CServerDlg::SOCKET_Select(SOCKET hSocket, int nTimeOut, BOOL bRead)
{
fd_set fdset;
timeval tv;
FD_ZERO(&fdset);
FD_SET(hSocket, &fdset);
nTimeOut = nTimeOut > 1000 ? 1000 : nTimeOut;
tv.tv_sec = 0;
tv.tv_usec = nTimeOut;
int iRet = 0;
if ( bRead ) {
iRet = select(0, &fdset, NULL , NULL, &tv);
}else{
iRet = select(0, NULL , &fdset, NULL, &tv);
}
if(iRet <= 0) {
return FALSE;
} else if (FD_ISSET(hSocket, &fdset)){
return TRUE;
}
return FALSE;
}