选择模型
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 }