现在的位置: 首页 > 综合 > 正文

winsock Select模型

2012年12月02日 ⁄ 综合 ⁄ 共 1735字 ⁄ 字号 评论关闭
Windows在非阻塞和阻塞模式下执行I/O操作。在阻塞模式下TCP对一个IP的端口只能执行完一个客户的请求才能处理下一个请求,各个请求之间排队按顺序执行,这就是同步。异步就是同时来两个或者多个请求,服务器就同时相应多个客户端。它们是并行执行的。

在阻塞模式和单线程下若一个I/O操作被阻塞那么整个程序都会被阻塞,如果条件不满足程序就会永远被锁死。

一下代码创建一个套节字并将其置为非阻塞模式
SOCKET s;
usigned long cmd;
int nStatus;
s=socket(AF_INET,SOCK_STREAM,0);
nStatus=ioctlsocket(s,FIOBIO,&cmd);
if(nStatus==SOCK_ERROR)
{
 //设置非阻塞模式失败
}
将一套接字设为非锁定阻塞后,windows API调用会立即返回,大多数情况下这些调用都会失败,返回WSAEWOULDBLOCK错误标识请求的操作在调用期间没有时间完成,由于非锁定调用会频繁返回WSAEWOULDBLOCK错误,所以程序员需要通过不断地检查函数返回代码半段一个套接字何时可供读写,为免去麻烦Winsock提供几种不同的套接字I/O模型对I/O进行管理。包括select(选择)、WSAEAsyncSelect(异步选择)、WSAEventSelect(事件选择)、Overlapped(重叠)以及Completion(完成端口)

Select模型就是为了防止在在阻塞模式的套接字里被锁死,避免在非阻塞套接字里重复检查WSAEWOULDBLOCK错误。

select()函数可以确定一个或多个套接字的状态,判断套接字上是否存在数据,或者能否向一个套接字写入数据。它既能防止应用程序在套接字处于阻塞模式时在一次I/O操作后被阻塞,同时也能防止在套接字处于非锁定模式中时,产生WSAEWOULDBLOCK错误
int select
(
int nfds,//可忽略,与Berkeley套接字兼容
fd_set *readfds,//指向等待可读性检查的套接字组的指针
fd_set *writefds,//指向等待可写性检查的套接字组的指针
fd_set *exceptfds,//指向等待错误检查的套接字组的指针
const struct timeval *timeout//是timeval结构数据,用于指定select()最多等待时间,对于阻塞操作则为NULL
)
在三个fd_set参数中至少有一个不为NULL,在任何不为空的集合中,必须包含至少一个套接字句柄,否则select()函数便没有任何可以等待的东西了
成功返回时,fd_set结构中将存有满足一定条件的套接字的子集,并且select()返回满足条件的套接字的数目。若超过timeval设定的时间便会返回0,若调用失败则返回SOCKET_ERROR。
struct timeval
{
 long tv_sec;//秒
 long tv_usec;//毫秒
}
若将超时值设置成(0,0)。则select()会立即返回,允许应用程序对select操作进行“轮询”。处于性能方面的考虑应避免这样的设置。
Winsock提供了FD_SETSIZE变量用于确定一个集合中最多的套接字描述数目,缺省为64位,可在包含winsock.h前用#define FD_SETSIZE来改变该值
FD_CLR(s,*set ):从集合set中删除套接字s
FD_ISSET(s,*set):若s为集合中的一员则为非零;否则为零
FD_SET(s,*set):向集合中添加套接字s
FD_ZERO(*set):将set初始化为空集NULL
如想测试一个套接字是否“可读”
(1)将套接字添加到readfds集合中
  fd_set fdread;
  FD_ZERO(&fdread);
  FD_SET(s,&fdread);
(2)调用select()函数
  select(0,&fdread,NULL,NULL,NULL);

(3)等待select()返回,若调用成功,则判断该套接字是否仍为readfds集合的一员,若答案是肯定的,便表明该套接字“可读”,可立即从它上面读取数据
 if(FD_ISSET(s,&fdread))
{
  //从套接字中读取数据
}

抱歉!评论已关闭.