在《unix网络编程》中,介绍了select模型可用于将多个阻塞的fd统一进行阻塞,其具体操作,以recv的操作为例总结如下:
FD_SET readSet; //fd的集合
FD_ZERO(&readSet); //初始化
while(1)
{
for(i=0; i<CONCOUNTS;i++)
{
if (pM->confd[i] >0)
{
FD_SET(pM->confd[i],&readSet);
/*其中pM->confd[i]为accept之后得到的fd,
*全部设置到监控fd的集合中
*/
}
}
int ret=select(0,&readSet,NULL,NULL,NULL);
/*有一个或多个fd接收到了数据,假设是n个,
*这时readSet已经发生了变化,仅剩n个fd在集合中
*/
for(i=0; i<CONCOUNTS;i++)
{
if(FD_ISSET(pM->confd[i],&readSet))
/*判断有哪n个fd在集合中,这n个fd接收到了数据*/
{
recvLength =recv(pM->confd[i],commandString,COMLENGTH,0);
/*直接调用recv,无需阻塞,正如《unix网络编程》所说,
*省去了等待数据到来的阻塞,其实fd的连接只有一个的话,
*直接调recv与select的结果一致的。
*/
if (recvLength >0)
{
printf("recv:%s\n",commandString);
memset(commandString,0,COMLENGTH);
SetEvent(pM->conEvent);
}
}
}
//循环,继续监听各个accept之后得到的fd
}
总结关键步骤:
- FD_SET(pM->confd[i],&readSet);//监听所有感兴趣的连接。
- int ret=select(0,&readSet,NULL,NULL,NULL);//有n个接受到数据,readSet仅剩这n个fd。
- FD_ISSET(pM->confd[i],&readSet);//得到这n个连接,并进行recv。