套接字Select模型是比较常用的一种I/O模型,利用该模型使得Windows Sockets应用程序可以在同一时间内
管理和控制多个套接字,该模型的核心就是select()函数----调用select()函数检查当前多个套接字的状态
----是否可读,可写,有异常。。。。。根据该函数的返回值,判断套接字的可读可写性,然后调用相应的
Windows Sockets API函数完成数据的发送和接收等操作。。。。
【阻塞模式】 套接字执行I/O操作时,如果执行操作的条件没有得到满足,线程会被阻塞在该调用的函数上,
程序不得不处于等待状态,该调用函数什么时候返回,不得而知;
【非阻塞模式】 套接字执行I/O操作时,无论在何种情况下,调用函数都会立即返回,软件设计人员需要编写
更多的代码,对函数返回的错误码(nErrCode)进行处理(GetLastError()),有时候在应用程序中
往往需要在一个循环体内反复调用该函数,直到该函数返回成功结果为止,这显然不是好办法。
【select()函数】
int select(int nfds, fd_set FAR* readfds, fd_set FAR* writefds, fd_set FAR* exceptfds const struct timeval FAR* timeout);
【0】nfds 可被忽略,与Berkeley套接字应用程序兼容
【1】readfds 具有可读性套接字集合的指针;
【2】writefds 具有可写性套接字集合的指针;
【3】exceptfds 检查错误套接字集合的指针;
【4】timeout 设置该select()函数等待时间
#define FD_SETSIZE 64
typedef struct fd_set
{
u_int fd_count;
SOCKET fd_addry[FD_SETSIZE];
}fd_set;
struct timeval
{
long tv_sec;
long tv_usec;
};
timeout == NULL; 表示无限等待,直到条件符合返回
timeout == 0; 立即返回
timeout == **** 表示等待****时间之后返回
FD_CLR(s, *set) 从set集合中删除s套接字
FD_ISSET(s, *set) 检查s是否是set集合中的一名成员
FD_SET(s, *set) 将套接字s加入到set集合中
FD_ZERO(*set) 将set集合初始化为空集合
常用代码结构
SOCKET listenSocket;
FD_SET allfd;
FD_SET readfd;
FD_SET writefd;
int reVal;
FD_ZERO(&allfd);
FD_SET(listenSocket, &allfd);
while(1)
{
FD_ZERO(readfd);
FD_ZERO(writefd);
readfd = allfd;
writefd = allfd;
reVal = select(0, &readfd, &writefd, NULL, NULL);
if(reVal == SOCKET_ERROR)
{
// 错误处理
}
if(reVal > 0)
{
for(int i = 0; i < allfd.fd_count; i++)
{
SOCKET sTmp = allset.fd_array[i];
if(FD_ISSET(sTmp, &readfd)) // 可读性 有数据可读 或者 有连接发起
{
if(sTmp == listenSocket) // 因为listenSocket 不断监听指定端口是否有连接发起,现在有链接发起
{
// 建立新的连接 SOCKET NewAcceptSocket = accept(listenSocket, NULL, NULL);
// ..........
}
else
{
// 有数据可以接受 RecvData()
// ..........
}
}
if(FD_ISSET(sTmp, &writefd))
{
// SendData()
// ...........
}
}
}
}