网络中的超时检测!

2019-07-13 01:53发布

在网络通信中,很多操作会使得进程阻塞    1.TCP套接字中的recv/accept/connect    2.UDP套接字中的recvfrom 超时检测的必要性
   1.避免进程在没有数据时无限制地阻塞
   2.当设定的时间到达时,进程会从原操作返回继续运行
以下是网络超时检测的3种设置方法   1-- 使用setsockopt 进行超时设置
    struct timeval
    {
     __time_t tv_sec;        /* Seconds.  */  秒
     __suseconds_t tv_usec;  /* Microseconds.  */ 微 
                          };      
    struct timeval  tv;
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    
   设置超时检测
    if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0){
      err_log("fail to setsockopt");
    }
  2-- 使用select 函数实现超时检测
    struct timeval {
     long    tv_sec;         /* seconds */
     long    tv_usec;        /* microseconds */
    };
   int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
   功能:允许一个进程监听多个文件描述符集合,阻塞等待,直到有一个或者多个文件描述符资源准备就绪,那么函数立刻返回。
   参数:nfds       最大的文件描述符加1
         readfds    读文件描述符集合
         writefds   写文件描述符集合
         exceptfds  异常的文件描述符集合
         timeout    如果设置为NULL,则一直阻塞等待
   返回值:成功  timeout 为 NULL 时 ,已经准备就绪的文件描述符的个数
                 timeout 不为NULL时 ,时间到达之前,有文件描述符准备就绪,那                  么返回准备就绪的文件描述符的个数时间到达之前,没有文件描述符  准备就绪那么返回0
           出错   -1
     
   注意:每次select之后成功之后,都会将集合中没有准备就绪的文件
      描述符给清楚掉,所以需要每次重新添加 
struct timeval  tv;     tv.tv_sec = 5;         tv.tv_usec = 0;                                                         ret = select(maxfd+1, &readfds, NULL, NULL, &tv);
   注意:每次调用select 函数之前,都应该对tv进行重新赋值
  3-- 使用alarm 定时器 ,实现超时检测
   int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
   功能:注册一个信号,设置信号的属性信息
   参数: signum  信号,不能是 SIGKILL , SIGSTOP
        act     信号新的属性行为
          oldact  信号当前的属性行为
   返回值: 成功 0
    出错 -1    struct sigaction {
    void     (*sa_handler)(int);  // 信号处理函数
    void     (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t   sa_mask;
    int        sa_flags;  // SA_RESTART 系统调用的自重启属性。
    void     (*sa_restorer)(void); 
   };
    
   struct sigaction act;
  
   // 注册闹钟信号
   sigaction(SIGALRM, NULL, &act);
    
   act.sa_handler = handler; // 设置信号处理函数
   act.sa_flags &= ~SA_RESTART; //设置自重启属性为假
   
   sigaction(SIGALRM, &act, NULL);
  
   alarm(5);