我们在写socket编程的时候,如果采用非阻塞的方式,往往会用到select函数:
int select( int maxfd, fd_set *preadfds,fd_set *pwritefds,fd_set *perrorfds,struct timeval *ptimeout);
一般这样用:
……
fd_set readfds;
struct timeval timeout={1,0};//1秒超时
……
while(1)
{
FD_ZERO(&readfds);
FD_SET(sock,&readfds);
ret = select(socket+1,&readfds,NULL,NULL,&timeout);
if(ret>0)
{
if(FD_ISSET(sock,&readfds))
{
recvfrom(socket,buffer,len,…);
……
}
}
……
}
以上是linux平台的select的用法,windows平台也类似,不过第一个参数maxfds可以随便填。这两个平台这样使用都没问题。但是笔者在td手机上,即大唐平台上应用,发现会死机(严格来讲,就是第二次跑到select,就阻塞不返回了)。
后来查出,这是大唐平台特殊之处,select函数会修改参数的timeout的值,每次select被调用返回后,timeout被修改为剩余的时间,所以当timeout被修改为0的时候,select函数就永远阻塞。
因此,需要在while循环里面重新给timeout赋值,才能使得程序正确运行:
……
fd_set readfds;
struct timeval timeout={1,0};//1秒超时
……
while(1)
{
FD_ZERO(&readfds);
FD_SET(sock,&readfds);
timeout={1,0};//需要在这重新赋值,程序才能正确运行
ret = select(socket+1,&readfds,NULL,NULL,&timeout);
if(ret>0)
{
if(FD_ISSET(sock,&readfds))
{
recvfrom(socket,buffer,len,…);
……
}
}
……
}
关于select函数其余参数的修改,可以参考相关的说明文档。需要说明的是,函数对自身参数的修改,是一个不好的设计,增加程序间的耦合,很容易出错。