套接字i/o模型

当套接字创建时,默认情况下是工作在阻塞模式。在阻塞模式下,执行i/o的winsock调用(如send()和recv())一直到操作完成时才返回。比如调用recv()函数,如果对应的缓冲区没有数据到来。调用者将会一直等待下去,直到有数据到达为止。

       如果有多个套接字连接时。为了避免出现一对套接字长时间占用,而其他套接字长时间得不到响应。就必须采用其他方式。可以采用多线程方式。即一个线程对应一个连接。通过server的CPU时间片轮转从而是每个套接字得到响应。除此以外,可以采用套接字i/o的异步方式在一个或者多个套接字上管理I/O。这样的I/O模型有6种。阻塞(blocking)模型、选择(select)模型、WSAAsyncSelect模型、WSAEventSelect模型、重叠(overlapped)模型、和完成端口(completion port)模型。

1>阻塞(blocking)模型

 对于以下函数调用:

int iResult = recv(s, buffer,1024);
        这是用来接收数据的,在默认的阻塞模式下的套接字里,recv会阻塞在那里,直到套接字连接上有数据可读,把数据读到buffer里后recv函数才会返 回,不然就会一直阻塞在那里。

        在单线程的程序里出现这种情况会导致主线程(单线程程序里只有一个默认的主线程)被阻塞,这样整个程序被锁死在这里,如果永 远没数据发送过来,那么程序就会被永远锁死。这个问题可以用多线程解决。

2>select模型

一般如果如果对某个套接字进行收取,如果没有数据,对阻塞模式而言,就会阻塞到有数据为止。
对于select模式,就先查询缓冲区是否有数据,如果有再收,这样就不会阻塞了。select就是这个原理,传入一个套接字集合作为参数,select函数检查套接字的缓冲区,返回满足条件的套接字集合,然后你对每一个满足条件的套接字调用收取函数,就能无阻塞的收取数据了。

比如下面代码:

.................

 //初始化一个套接字集合fdSocket,添加套接字句柄到这个集合
 fd_set fdSocket;  //所有可用套接字集合
 FD_ZERO(&fdSocket);
 FD_SET(sListen,&fdSocket);
 while (1)
 {
  //将fdSocket的一个拷贝fdRead传递给select函数
  //当有事件发生时,select函数移除fdRead集合中没有未决i/o操作的套接字句柄,并返回
  fd_set fdRead = fdSocket;
  int nRet = ::select(0, &fdRead, NULL, NULL, NULL);
  if (nRet > 0)
  {
   //确定又哪些套接字有未决i/o,并进一步处理这些i/o
   for (int i = 0; i < (int)fdSocket.fd_count; ++i)
   {
    if (FD_ISSET(fdSocket.fd_array[i], &fdRead))
    {
     if (fdSocket.fd_array[i] == sListen)  //监听的套接字收到连接
     {
      if (fdSocket.fd_count < FD_SETSIZE)
      {    
       sockaddr_in addrRemote;
       int nAddrLen = sizeof(addrRemote);
       SOCKET sNew = ::accept(sListen, (SOCKADDR *)&addrRemote, &nAddrLen);
       FD_SET(sNew, &fdSocket);
       printf("接收到连接(%s)/n", ::inet_ntoa(addrRemote.sin_addr));
      }
      else
      {
       printf("Too much connections!/n");
       return 0;
      }
     }
     else
     {//其他套接字有数据(处于可读状态),于是服务器端接收数据
      char szText[256];
      int nRecv = ::recv(fdSocket.fd_array[i], szText, strlen(szText), 0);
      if (nRecv > 0)
      {
       szText[nRecv] = '/0';
       printf("接收到数据:%s/n", szText);
      }
      else
      {
       ::closesocket(fdSocket.fd_array[i]);
       FD_CLR(fdSocket.fd_array[i], &fdSocket);
      }
     }
    }
   }
  }
  else
  {
   printf("Failed select().../n");
   break;
  }
 } 
..........

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值