网络编程(4)超时接收

1.网络接收超时

一般情况下网络接收数据都采用阻塞属性,就等于一直等待对方数据到达。有的场合中我们可能不需要一直等待,因为可能会没有结果,这是可以使用超时接收,在规定的时间内如果没有数据到达。,则超时退出。

主要方法有三种:

  • 使用多路复用的slect 函数设置超时时间
  • 设置闹钟,当设置时间到达时将会产生一个SIGALRM信号,表示超时
  • 设置套接字的属性为超时属性

2.多路复用

例题: 写一个服务器,使用select函数监听客户端的状态,如果客户端在3秒内没有发送数据,则超时接收。

思路:

使用select函数设置监听客户端状态

如果客户端在规定时间内没有数据到达则超时退出

关键代码 :

// 配置超时时间
struct timeval time_val ;
time_val.tv_sec = 5 ;
time_val.tv_usec = 0 ;

// 设置多路复用集合
fd_set set ;
FD_ZERO(&set); // 清空 集合
FD_SET(connect_fd , &set); // 添加 套记字到集合中
FD_SET(STDIN_FILENO , &set); // 添加标准输入到集合中

 // 找到描述符最大值
max_fd = connect_fd > STDIN_FILENO ? connect_fd : STDIN_FILENO ;
// 等待描述符状态变化并设置超时 5秒
int ret_val = select(max_fd+1, &set , NULL ,NULL, &time_val);
if( ret_val == 0 )
{
    printf("接收数据超时!!\n");
    return -1 ;    
}

3.设置闹钟

闹钟这种方式类似于信号驱动,信号驱动当收到信号时,证明有数据发送过来。闹钟使用alarm函数来提前设定一个时间,当时间到达时,回自动产生一个信号 14) SIGALRM。

思路:

  1. 使用signal函数设置好捕获闹钟信号,并设置好响应处理函数。
  2. 使用alarm()函数设置一个闹钟时间
  3. 当闹钟时间结束时产生一个 SIGALRM 信号
  4. 当捕获到闹钟信号则运行对应的响应函数
  5. 重新设置闹钟

API 接口

头文件:
    #include <unistd.h>
函数原型:
      unsigned int alarm(unsigned int seconds);
参数分析:
    seconds --> 闹钟时间  (秒)
返回值:
    成功返回设置的剩余时间
    失败 0 

4.设置套接字超时属性

在Linux下,建立套接字都是阻塞属性.我们设置一个超时属性给套接字,这样读取套接字数据时,在规定的时间会阻塞,但是在规定的时间之外,读取失败。

思路:

  1. 获得一个连接套接字
  2. 使用函数设置超时属性setsockopt()
  3. 正常玩耍,当接收函数返回-1时就是超时的时候了

接口API

获得属性/设置属性
头文件:
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

函数原型:
       int getsockopt(int sockfd, int level, int optname,
                      void *optval, socklen_t *optlen);
       int setsockopt(int sockfd, int level, int optname,
                      const void *optval, socklen_t optlen);
参数分析:
    sockfd --> 需要设置的已连接套接字
    level --> 优先级
        SOL_SOCKET:套接字
        IPPROTO_IP:IP优先级
        IPPRO_TCP:TCP优先级
    optname --> 属性名
    optval --> 属性的值 使能为1,失能为0
    optlen --> 属性的值类型的长度
返回值:
    成功  0 
    失败 -1
时间结构体:
struct timeval {
       long    tv_sec;         /* seconds */   秒
       long    tv_usec;        /* microseconds */   微秒
   };

补充optname:
===========================SOL_SOCKET====================================:
optname选项名字                                           optlen的大小
SO_BROADCAST       允许发送广播数据            int 
SO_DEBUG        允许调试                int 
SO_DONTROUTE      不查找路由               int 
SO_ERROR        获得套接字错误             int 
SO_KEEPALIVE      保持连接                int 
SO_LINGER        延迟关闭连接              struct linger 
SO_OOBINLINE      带外数据放入正常数据流         int 
SO_RCVBUF        接收缓冲区大小             int 
SO_SNDBUF        发送缓冲区大小             int
SO_RCVLOWAT       接收缓冲区下限             int 
SO_SNDLOWAT       发送缓冲区下限             int 
SO_RCVTIMEO       接收超时                struct timeval 
SO_SNDTIMEO       发送超时                   struct timeval
SO_REUSEADDR       允许重用本地地址和端口          int 
SO_TYPE         获得套接字类型             int 
SO_BSDCOMPAT      与BSD系统兼容              int 

=========================IPPROTO_IP=======================================
IP_HDRINCL       在数据包中包含IP首部          int 
IP_OPTINOS       IP首部选项               int 
IP_TOS         服务类型 
IP_TTL         生存时间                int 
IP_ADD_MEMBERSHIP       加入组播                            struct ip_mreq

=========================IPPRO_TCP======================================

TCP_MAXSEG       TCP最大数据段的大小           int 
TCP_NODELAY       不使用Nagle算法             int 

核心代码:

struct timeval v;
v.tv_sec = 5;
v.tv_usec = 0;

setsockopt(connfd,SOL_SOCKET,SO_RCVTIMEO,&v,sizeof(v));


n = read(connfd,buf,sizeof(buf));
if(n == -1)    ---> 超时,5秒内没有数据
{
    printf("timeout!\n");
}

if(n > 0)    --> 5秒内有数据
{
    printf("from client:%s",buf);
    if(strncmp(buf,"quit",4) == 0)
    {
        break;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值