socket select模型

传统的socket通信收发数据是阻塞式的,也就是说当一个socket recv时,server socket都不能响应client socket的连接请求,会产生堵塞。

采用多线程的方式,为每一个socket连接创建一个子线程取进行阻塞式的I/O开销太大,服务器资源伤不起。

这时候我们便可以采取select模型。

select允许进程指示内核等待多个事件中的任何一个发生,并仅在有一个或多个事件发生或经历一段指定时间后才唤醒它。select告诉内核对哪些描述字感兴趣以及等待多长时间。这就是所谓的非阻塞模型,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高。提供了一种异步I/O的方式。

select函数原型如下:

int select
(
     int nfds, //Winsock中此参数无意义
     fd_set* readfds, //进行可读检测的Socket
     fd_set* writefds, //进行可写检测的Socket
     fd_set* exceptfds, //进行异常检测的Socket
     const struct timeval* timeout //非阻塞模式中设置最大等待时间
 )

select函数三个集合中至少有一个监视集合不能为空,其他两个都可以为空。


最后一个参数timeout值有下列三种情况:

1.置为NULL的话,设置套接字为阻塞状态,一定要等到相应的套接字完成相应的操作为止才能结束阻塞。

2.置为0s 0ms,就变成了一个纯粹的非阻塞函数,不管套接字状态有没有变化,都立刻返回继续执行,无变化返回0,有变化返回一个正值。

3.置为大于0,这就是等待的超时时间,即socket在timeout时间内阻塞,若timeout时间之内socket状态如完成I/O操作就返回了,否则在超时后不管怎样一定返回。


返回值意义:

负值:select调用错误。

正值:socket可以I/O

0:等待超时,没有可以I/O的socket


和select模型紧密结合的四个宏:

FD_CLR( s,*set) 从队列set删除句柄s。

FD_ISSET( s, *set) 检查句柄s是否存在与队列set中。

FD_SET( s,*set )把句柄s添加到队列set中。

FD_ZERO( *set ) 把set队列初始化成空队列。


select模式依赖于select函数,其思想就是让select函数对传入的fd_set中的套接字进行监视,如果没有什么事情发生就将之前监视的fd_set中的套接字清空。以下是一个select模型的例子:

timeval outTime;
outTime.tv = 1;   //设置等待时间为1s
outTime.usec = 0; //毫秒
fd_set fdread;
while(true)
{
   FD_ZERO(&fdread);
   FD_SET(sessionSock, &fdread) //sessionSock为之前创建的会话套接字
   select(0, &fdread, NULL, NULL, &outTime);
   if(FD_ISSET(sessionSock, &fdread))//判断套接字是否还在集合中
   {
      recv_cnt = recv(sessionSock, buf, bufSize, 0);
   }
   else
   {
      //没有数据写入,进行其他操作
   }
}

所谓的异步还是得借助于多线程,借助于多线程来完成异步。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值