Winsock 网络编程 Socket模型之Select模型

前言:
讲一下套接字模式和套接字I/O模型的区别。先说明一下,只针对Winsock
套接字模式:阻塞套接字和非阻塞套接字。或是叫同步套接字和异步套接字。
套接字模型:描述如何对套接字的I/O行为进行管理
Winsock提供的I/O模式一共有五种:
Select模型,WSAAsyncSelect模型,WSAEventSelect模型,Overlapped模型(重叠IO),Completion模型(完成IO)


一、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))    //发现可写  
                 {
                         //发送缓冲区未满可以发送
                         //如果失败 删除此元素
                 }
         }
  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值