Socket Select IO模型

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模型的举例:
代码
 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         }
posted @ 2011-01-06 16:48  zhouli  阅读(508)  评论(0编辑  收藏  举报