套接字Select I/O模型

来源:互联网 发布:三维效果图设计软件 编辑:程序博客网 时间:2024/05/10 10:57
select模型


select(选择)模型是winsock中常见的I/O模型。之所以称其为“select模型”,是由于它的
“中心思想”是利用select函数,实现对I/O的管理!最初设计该模型时,主要面向的是某些使用
Unix操作系统的计算机,它们采用的是Berkeley套接字方案。select模型已经集成到Winsock1.1中。


1


.通过调用select函数可以确定一个或多个套接字的状态,判断套接字上是否有数据,或
者能否向一个套接字写入数据。 
 int select (int nfds,                                                   //忽略
                fd_set FAR *readfds,                                //等待可读性检查的套接字组的地址
                fd_set FAR *writefds,                               //等待可写性检查的套接字组的地址
                fd_set FAR *exceptfds,                              //等待错误检查的套接字组的地址
                const struct timeval FAR *timeout);         //struct timeval结构体地址,select() 最多等待的时间
//返回值       0--超时,SOCKET_ERROR--失败
//说明:此函数的作用是删除fd_set结构体中没有IO操作的套接字
/*注意:在3个套接字组中至少有一个不为NULL;在非空集合中必须包含一个套接字句柄。
     如果timeout设为(0,0),select() 会立即返回,允许应用程序对select操作进行“轮询”。
     如:
        fd_set fdread;
        FD_ZERO(&fdread);
        FD_SET(s, &fdread);
        select(0, &fdread, NULL, NULL, NULL);
        if(FD_ISSET(s, &fdread))
        {
                //套接字可读
        }
*/




2.管理套接字的结构体
定义:
typedef struct fd_set {
        u_int   fd_count;               /* how many are SET? */  //元素的个数
        SOCKET  fd_array[FD_SETSIZE];   /* an array of SOCKETs */
} fd_set;


对struct fd_set结构体操作的宏
FD_SETSIZE              容量,指定fd_array数组大小,默认为64,也可自己修改宏
FD_ZERO(*set)           置空,使数组的元素值都为3435973836,元素个数为0.
FD_SET(s, *set)         添加,向 struct fd_set结构体添加套接字s
FD_ISSET(s, *set)       判断,判断s是否为 struct fd_set结构体中的一员
FD_CLR(s, *set)         删除,从 struct fd_set结构体中删除成员s    


3.用Select模型获取网络事件

    FD_SET AllSockFd;        //装有所有的套接字    FD_ZERO(&AllSockFd);    AllSockFd = ClientSockFd ;    FD_SET(ListenSock, &AllSockFd);    FD_SET ReadSockFd;    //读集合    FD_SET WriteSockFd;    //写集合    while(1)    {        FD_ZERO(&ReadSockFd);        FD_ZERO(&WriteSockFd);        ReadSockFd = AllSockFd;        WriteSockFd = AllSockFd;        int nRet = select(0, &ReadSockFd, &WriteSockFd, NULL, NULL);            if(SOCKET_ERROR == nRet)        {            continue;        }        //有请求事件发生        if (FD_ISSET(ListenSock, &ReadSockFd))        {            //接受请求            SOCKET ClientSock;            u_short Port;            bool nRe = (*(Pam.pListenSock)).Accept(&ClientSock, 0, &Port);            if(nRe)            {                FD_SET(ClientSock, Pam.pClientSockFd);                //设置套接字发送缓冲区80K                int nBuf = SOCKET_BUFF;                int nBufLen = sizeof(nBuf);                int nRe = setsockopt(ClientSock, SOL_SOCKET, SO_SNDBUF, (char*)&nBuf, nBufLen);                if(SOCKET_ERROR == nRe)                    AfxMessageBox("setsockopt error!");                    //检查缓冲区是否设置成功                nRe = getsockopt(ClientSock, SOL_SOCKET, SO_SNDBUF, (char*)&nBuf, &nBufLen);                if(SOCKET_BUFF != nBuf)                    AfxMessageBox("检查缓冲区:setsockopt error!");                else                    AfxMessageBox("已连接客户端!");            }        }        //判断是否可读或可写        for(u_int n = 0;n < ClientSockFd.fd_count;n++)        {                if(FD_ISSET(ClientSockFd.fd_array[n], &ReadSockFd))        //发现可读                {                                //接收数据                        //如果失败 删除此元素                        }                if(FD_ISSET(ClientSockFd.fd_array[n], &WriteSockFd))    //发现可写                  {                        //发送缓冲区未满可以发送                        //如果失败 删除此元素                }        }    }




0 0