先帖几个链接:
http://www.cppblog.com/CppExplore/archive/2008/03/14/44509.aspx
http://www.cppblog.com/myjfm/archive/2011/10/26/159093.aspx
http://www.cppblog.com/just51living/archive/2011/07/28/151995.html
http://buluzhai.iteye.com/blog/1013451
再次感叹伟大的互联网,下面开始正题!
其中 timeout
1.timeout=NULL(阻塞:select将一直被阻塞,直到某个文件描述符上发生了事件)
2.timeout所指向的结构设为非零时间(等待固定时间:如果在指定的时间段里有事件发生或者时间耗尽,函数均返回0)
原因:进行Socket通信是如果通过ioctlsocket设置为非阻塞模式时,要进行查询的话,需要while()循环,还有其他方式吗?
解释:
a\ fd_set fd_set是一组文件描述字(fd)的集合,它用一位来表示一个fd
typedef struct fd_set
{ u_int fd_count; SOCKET fd_array[FD_SETSIZE];
} fd_set;
b\FD_SET FD_SET(fd, &set); /*将fd加入set集合*/
c\ FD_ZERO FD_ZERO(&set); /*将set清零使集合中不含任何fd*/
d\FD_CLR FD_CLR(fd, &set); /*将fd从set集合中清除*/
e\FD_ISSET FD_ISSET(fd, &set); /*测试fd是否在set集合中*/
实例:
socket s; ..... fd_set set; while(1) { FD_ZERO(&set);//将你的套节字集合清空 FD_SET(s, &set);//加入你感兴趣的套节字到集合,这里是一个读数据的套节字s select(0,&set,NULL,NULL,NULL);//检查套节字是否可读, //很多情况下就是是否有数据(注意,只是说很多情况) //这里select是否出错没有写 if(FD_ISSET(s, &set) //检查s是否在这个集合里面, { //select将更新这个集合,把其中不可读的套节字去掉 //只保留符合条件的套节字在这个集合里面 recv(s,...); } //do something here }
后续
理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。
(1)执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。
(2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)
(3)若再加入fd=2,fd=1,则set变为0001,0011
(4)执行select(6,&set,0,0,0)阻塞等待
下面还有一个复杂一些的应用: //这段代码将指定测试Socket的描述字的可读可写性,因为Socket使用的也是fd uint32 SocketWait(TSocket *s,bool rd,bool wr,uint32 timems) { fd_set rfds,wfds; #ifdef _WIN32 TIM tv; #else struct tim tv; #endif 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: return 0; case (-1): 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; }; }