代码
SOCKET sListen = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
SOCKADDR_IN sin;
sin.sin_family = AF_INET;
sin.sin_addr.S_un.S_addr = INADDR_ANY;
sin.sin_port=htons(CDownCfg::GetUDPClientPort());
::bind(sListen,(SOCKADDR *)&sin,sizeof(sin));
int iMode = 1; //0:阻塞
ioctlsocket(sListen,FIONBIO,(u_long FAR*) &iMode);//非阻塞设置
SOCKADDR_IN addrRemote;
int nRemote = sizeof(SOCKADDR_IN);
//////////////////////////////////////////////////////////////////////////////
//Select
fd_set fdSocket;
FD_ZERO(&fdSocket);
FD_SET(sListen,&fdSocket);
//////////////////////////////////////////////////////////////////////////////
//超时限制为5秒
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
while (TRUE)
{
int nSele = select(0,&fdSocket,NULL,NULL,&timeout);
char recvbuf[256];
int nRet = 0;
if (nSele>0)
nRet = ::recvfrom(sListen,recvbuf,256,0,(SOCKADDR*)&addrRemote,&nRemote);
else
break;
}
这是一段UDP服务器的代码,场景是在你广播之后收听应答。如果超时5秒内没有出现应答,则不再收听,认为所有应答已经接收完毕。注意其中select的用法。
《Windows网络通信与程序设计》一书中很早就有提到过这个函数的常规用法,由此观之,很多函数的深入理解不在于说按照常规你可以怎么走,而是说,这个函数可以给你提供怎样的可能性。而仔细深究下去,有一个疑问,为什么可以先select再去recvfrom。select是返回所有发生网络事件的套接字的总和,那么我现在根本没有去recvfrom,为什么就发生了网络事件呢?也许这就是UDP的特殊之处所在。目前这个问题只能留待以后去理解。