在winsock的编程中,winsock有许多阻塞函数。比如:accept,recv等。线程执行到这个函数时就会挂起,等条件满足时再继续执行。比如,服务器端accept,只有当客户端执行connect时,才会接着往下执行。而使用select模型,进行通信,可以避免线程挂起,减少资源消耗。select模型,使用范围很广,通常用作网络通讯的客户端,或者连接数较小的服务端,如局域网游戏。
select模型要用的结构和函数如下:
fd_set,可以理解为文件句柄的一个集合,sock也可认为是一个文件句柄。
timeval,用来表示时间,结构体中的tv_sec表示秒,tv_usec表示毫秒。
int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout); 通过这个函数进行查询,返回值是所有socket的数目,这些socket包含在fd_set结构中,并且已完成准备工作。如果超时,则返回0,如果出错,则返回SOCKET_ERROR。
使用过程一般遵循以下步骤:
1、声明FD_SET变量
2、初始化FD_SET变量
3、关联文件句柄和FD_SET变量
4、设置超时时间。
5、调用select看是否有可用的socket
6、调用FD_ISSET看究竟是哪个socket可用,对这个socket进行进一步操作。
源码如下:(或者见http://download.csdn.net/detail/cloud95/4186484)
while(TRUE)
{
printf("nRetCode!=SOCKET_ERROR) while(TRUE)\t");
FD_SET writefd;
FD_SET readfd;
FD_ZERO(&writefd); //初始化
FD_ZERO(&readfd);
FD_SET(ClientSocket,&writefd); //关联FD_SET结构和文件句柄
FD_SET(ServerSocket,&readfd);
timeval timeout={3,0}; //select等待3秒,3秒轮询,要非阻塞就置0
nRetCode=select(0, &writefd, &readfd, NULL, &timeout);
if(SOCKET_ERROR==nRetCode)
{
printf("Select错误");
return nRetCode ;
}
else if(nRetCode>0)
{
if(FD_ISSET(ClientSocket,&writefd)) //测试sock是否可写,数据是来自哪个socket,其实对于非阻塞函数一般不做判断
{
printf("writefd启动");
if(FALSE ==SendData(ServerSocket))//发送数据接收数据
{
printf("SendData(ServerSocket)未成功");
return 0;
}
}
if(FD_ISSET(ServerSocket,&readfd)) //测试sock是否可读,数据是来自哪个socket,
{
printf("readfd启动\n");
if (FALSE == RecvData(ServerSocket)) //接收数据
{
printf("RecvData(ServerSocket)失败");
return 0;
}
}
}
}