选择模型
fd_set结构可以把多个套接字连在一起,形成一个套接字集合
typedef struct fd_set{
u_int fd_count;//下面数组的大小
SOCKET fd_array[FD_SETSIZE];//套接字句柄数组
}fd_set;
网络事件:
readfds集合:数据可读,连接关闭,重启或者中断
writefds集合:数据能发送
exceptfds集合:OOB数据可读
设置超时:
如果为null为无限阻塞,知道有网络事件发生
typedef struct timeval{
long tv_sec;//指示等待多少秒
long tv_usec;//指示等待多少毫秒
}timeval;
应用举例
1 初始化fdSocket集合,添加监听套接字句柄
2 将fdSocket集合拷贝fRead传递给select函数,当有事件发生的时候,select函数移除fRead中没有未决IO操作的句柄,然后返回
3 比较原来的fdSocket集合,与select处理过的fdRead集合,确定哪些套接字有未决IO并处理这些IO
4 回到2进行选择
1 CInitSock theSock;//初始化winsock库
2 int main()
3 {
4 USHORT nPort=4567;//此服务器监听的端口号
5 //创建监听套接字
6 SOCKET sListen=::listen(AF_INET,SOCK_STREAM,IPPROTO_TCP);
7 sockaddr_in sin;
8 sin.sin_family = AF_INET;
9 sin.sin_port = htons(nPort);
10 sin.sin_addr.S_un.S_addr = INADDR_ANY;
11 //绑定套接字到本地机器
12 if(::bind(sListen,(sockaddr*)&sin,sizeof(sin))==SOCKET_ERROR)
13 {
14 printf("Failed bind()!\n");
15 return 0;
16 }
17 //进入监听模式
18 ::listen(sListen,5);
19
20 //select模型处理过程
21 ////////////////////////////////////////////////////////////////////////////
22 // 1 初始化fdSocket集合,添加监听套接字句柄
23 fd_set fdSocket;//所有可用套接字集合
24 FD_ZERO(&fdSocket);
25 FD_SET(sListen,&fdSocket);
26 while(TRUE)
27 {
28 ////////////////////////////////////////////////////////////////////////
29 //2 将fdSocket集合拷贝fRead传递给select函数,当有事件发生的时候,select函数移除fRead中没有未决IO操作的句柄,然后返回
30 fd_set fdRead = fdSocket;
31 int nRet = ::select(0,&fdRead,NULL,NULL,NULL);
32 if(nRet>0)
33 {
34 ///////////////////////////////////////////////////////////////////
35 // 3 比较原来的fdSocket集合,与select处理过的fdRead集合,确定哪些套接字有未决IO并处理这些IO
36 for(int i=0;i<(int)fdSocket.fd_count;i++)
37 {
38 if(FD_ISSET(fdSocket.fd_array[i],&fdRead))
39 {
40 if(fdSocket.fd_array[i]==sListen)// 1 监听套接字连接新连接
41 {
42 sockaddr_in addrRemote;
43 int nAddrLen = sizeof(addrRemote);
44 SOCKET sNew = ::accept(sListen,(SOCKADDR*)&addrRemote,&nAddrLen);
45 FD_SET(sNew,&fdSocket);
46 printf("接收到连接(%s)\n",::inet_ntoa(addrRemote.sin_addr));
47 }
48 else
49 {
50 printf("Too much connections!\n");
51 continue;
52 }
53 }
54 else
55 {
56 char szText[256];
57 int nRecv = ::recv(fdSocket.fd_array[i],szText,strlen(szText),0);
58 if(nRecv > 0)//可读
59 {
60 szText[nRecv] = '\0';
61 printf("接收到数据:%s\n",szText);
62 }
63 else//连接关闭或者重启
64 {
65 ::closesocket(fdSocket.fd_array[i]);
66 FD_CLR(fdSocket.fd_array[i],&fdSocket);
67 }
68 }
69 }
70 }
71 else
72 {
73 printf("Failed select()!\n");
74 break;
75 }
76 }
77 return 0;
78 }