select技术主要由一个函数和几个宏来提供支持:
/*
* 功能:监视多个文件描述符,直到有一个或多个文件描述符准备好做某种IO操作时返回
* 返回:当调用成功时,返回已准备好的文件描述符个数;发生错误时返回-1,可以通过errno得到错误类型
* 参数:
* nfds - 后面三个文件描述符集合中最大的文件描述符加1(想想为什么?)
* readfds - 等待进行读操作的文件描述符,指针传递,在select返回时会改变这个参数的值,只保留已准备好的文件描述符
* writefds - 等待进行写操作的文件描述符,指针传递,在select返回时会改变这个参数的值,只保留已准备好的文件描述符
* exceptfds - 监视异常的文件描述符号,很少用到
* timeout - 程序会在select调用的地方阻塞,你可以通过设置超时让程序可以在一定时间间隔后继续执行
*/
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
/*
* 功能:将指定文件描述符从指定的描述符集合中清除
* 参数:
* fd - 文件描述符
* set - 文件描述符集合
*/
void FD_CLR(int fd, fd_set *set);
/*
* 功能:检查一个文件描述符是否在集合中
* 返回:存在时返回非0整数,不存在则返回0
* 参数:
* fd - 文件描述符
* set - 文件描述符集合
*/
int FD_ISSET(int fd, fd_set *set);
/*
* 功能:设置一个文件描述符到集合中
* 参数:
* fd - 文件描述符
* set - 文件描述符集合
*/
void FD_SET(int fd, fd_set *set);
/*
* 功能:将一个文件描述符集合清零
* 参数:
* set - 文件描述符集合
*/
void FD_ZERO(fd_set *set);
下面是select模型的举例:/*
* 功能:监视多个文件描述符,直到有一个或多个文件描述符准备好做某种IO操作时返回
* 返回:当调用成功时,返回已准备好的文件描述符个数;发生错误时返回-1,可以通过errno得到错误类型
* 参数:
* nfds - 后面三个文件描述符集合中最大的文件描述符加1(想想为什么?)
* readfds - 等待进行读操作的文件描述符,指针传递,在select返回时会改变这个参数的值,只保留已准备好的文件描述符
* writefds - 等待进行写操作的文件描述符,指针传递,在select返回时会改变这个参数的值,只保留已准备好的文件描述符
* exceptfds - 监视异常的文件描述符号,很少用到
* timeout - 程序会在select调用的地方阻塞,你可以通过设置超时让程序可以在一定时间间隔后继续执行
*/
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
/*
* 功能:将指定文件描述符从指定的描述符集合中清除
* 参数:
* fd - 文件描述符
* set - 文件描述符集合
*/
void FD_CLR(int fd, fd_set *set);
/*
* 功能:检查一个文件描述符是否在集合中
* 返回:存在时返回非0整数,不存在则返回0
* 参数:
* fd - 文件描述符
* set - 文件描述符集合
*/
int FD_ISSET(int fd, fd_set *set);
/*
* 功能:设置一个文件描述符到集合中
* 参数:
* fd - 文件描述符
* set - 文件描述符集合
*/
void FD_SET(int fd, fd_set *set);
/*
* 功能:将一个文件描述符集合清零
* 参数:
* set - 文件描述符集合
*/
void FD_ZERO(fd_set *set);
代码
1 SOCKET m_sockSrv = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
2 if (m_sockSrv == INVALID_SOCKET)
3 {
4 cout << "Error: " << WSAGetLastError() << endl;
5 return false;
6 }
7 SOCKADDR_IN addrSrv;
8 addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
9 addrSrv.sin_family = AF_INET;
10 addrSrv.sin_port = htons(nPort);
11
12 int iRet;
13 iRet = bind(m_sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
14 if (iRet == SOCKET_ERROR)
15 {
16 cout << "Bind error! " << WSAGetLastError << endl;
17 return false;
18 }
19
20 iRet = listen(m_sockSrv, LISTEN_MAX_LINK);
21 if (iRet == SOCKET_ERROR)
22 {
23 cout << "Listen error! " << WSAGetLastError << endl;
24 return false;
25 }
26
27 fd_set fdSocket; //所有的可用套接字集合
28 FD_ZERO(&fdSocket);
29 FD_SET(m_sockSrv,&fdSocket);
30 char buf[1024] = {0};
31 int nLength = 0;
32 while(TRUE)
33 {
34 fd_set fdRead = fdSocket;
35 int nRet = ::select(0, &fdRead, NULL, NULL, NULL);
36 if (nRet)
37 {
38 for (int i = 0; i < (int)fdSocket.fd_count; i++)
39 {
40 if (FD_ISSET(fdSocket.fd_array[i], &fdRead))
41 {
42 if (fdSocket.fd_array[i] == m_sockSrv)
43 {
44 if (fdSocket.fd_count < FD_SETSIZE)
45 {
46 sockaddr_in addrRemote;
47 int nAddrLen = sizeof(addrRemote);
48 SOCKET sNew = ::accept(m_sockSrv, (SOCKADDR*)&addrRemote, &nAddrLen);
49 FD_SET(sNew, &fdSocket);
50 TRACE("接收到连接(%s)\n",::inet_ntoa(addrRemote.sin_addr));
51 }
52 else
53 {
54 TRACE("连接数太多!");
55 continue;
56 }
57 }
58 else
59 {
60 nLength = ::recv(fdSocket.fd_array[i],buf,sizeof(recv_struct),0);//recv_struct为接收结构体
61 if ( nLength > 0)
62 {
63 //读取接收缓冲区
64
65 }
66 else
67 {
68 ::closesocket(fdSocket.fd_array[i]);
69 FD_CLR(fdSocket.fd_array[i],&fdSocket);
70 }
71 }
72 }
73 }
74 }
75 else
76 {
77 printf("Failed select()\n");
78 break;
79 }
80 }
2 if (m_sockSrv == INVALID_SOCKET)
3 {
4 cout << "Error: " << WSAGetLastError() << endl;
5 return false;
6 }
7 SOCKADDR_IN addrSrv;
8 addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
9 addrSrv.sin_family = AF_INET;
10 addrSrv.sin_port = htons(nPort);
11
12 int iRet;
13 iRet = bind(m_sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
14 if (iRet == SOCKET_ERROR)
15 {
16 cout << "Bind error! " << WSAGetLastError << endl;
17 return false;
18 }
19
20 iRet = listen(m_sockSrv, LISTEN_MAX_LINK);
21 if (iRet == SOCKET_ERROR)
22 {
23 cout << "Listen error! " << WSAGetLastError << endl;
24 return false;
25 }
26
27 fd_set fdSocket; //所有的可用套接字集合
28 FD_ZERO(&fdSocket);
29 FD_SET(m_sockSrv,&fdSocket);
30 char buf[1024] = {0};
31 int nLength = 0;
32 while(TRUE)
33 {
34 fd_set fdRead = fdSocket;
35 int nRet = ::select(0, &fdRead, NULL, NULL, NULL);
36 if (nRet)
37 {
38 for (int i = 0; i < (int)fdSocket.fd_count; i++)
39 {
40 if (FD_ISSET(fdSocket.fd_array[i], &fdRead))
41 {
42 if (fdSocket.fd_array[i] == m_sockSrv)
43 {
44 if (fdSocket.fd_count < FD_SETSIZE)
45 {
46 sockaddr_in addrRemote;
47 int nAddrLen = sizeof(addrRemote);
48 SOCKET sNew = ::accept(m_sockSrv, (SOCKADDR*)&addrRemote, &nAddrLen);
49 FD_SET(sNew, &fdSocket);
50 TRACE("接收到连接(%s)\n",::inet_ntoa(addrRemote.sin_addr));
51 }
52 else
53 {
54 TRACE("连接数太多!");
55 continue;
56 }
57 }
58 else
59 {
60 nLength = ::recv(fdSocket.fd_array[i],buf,sizeof(recv_struct),0);//recv_struct为接收结构体
61 if ( nLength > 0)
62 {
63 //读取接收缓冲区
64
65 }
66 else
67 {
68 ::closesocket(fdSocket.fd_array[i]);
69 FD_CLR(fdSocket.fd_array[i],&fdSocket);
70 }
71 }
72 }
73 }
74 }
75 else
76 {
77 printf("Failed select()\n");
78 break;
79 }
80 }