首页 > 代码库 > 用alarm()为recvfrom设置定时器

用alarm()为recvfrom设置定时器

  因为项目需要,需要以5s为周期,收集广播信息,所以就要用到定时器和recvfrom函数,而在实用的过程中发现,5s到了,而程序仍然处于阻塞状态,一直纠结了好久,才找到问题所在,在此mark一下,以备后期回顾。


  归根结底,原因在于使用的signal()函数:signal()是重启函数,超时以后会自动启动已阻塞的函数,而不是中断它的执行,如recvfrom,给人的感觉就是使用了alarm,但依然阻塞在了recvfrom上,不往下执行。但在中断处理函数中用printf函数打印一条消息,就会发现,其实它是中断过的,只是返回后又阻塞在了recvfrom上而已。
 
  而使用sigaction函数,可以设置是否要重启函数,即alarmact.sa_flags = SA_NOMASK;选项,它会中断已阻塞的函数,使程序继续往下执行。而SA_RESTART选项则等同于signal效果,会重启函数,阻塞在recvfrom上。

#include <stdio.h>#include <string.h>#include <signal.h>#include <sys/socket.h>#include <errno.h>#include <netinet/in.h>int n;char recvbuf[1024];void listen_board();static void dealSigAlarm(int sigo){    n = -1;    printf("alarm interrupt!\n");    return;//just interrupt the recvfrom()}void main(){    struct sigaction alarmact;//  signal(SIGALRM,dealSigAlarm);    bzero(&alarmact,sizeof(alarmact));    alarmact.sa_handler = dealSigAlarm;//  alarmact.sa_flags = SA_RESTART;    alarmact.sa_flags = SA_NOMASK;    sigaction(SIGALRM,&alarmact,NULL);    listen_board();}void listen_board(){    int sock;    struct sockaddr_in fromaddr;    int len = sizeof(struct sockaddr_in);    bzero(&fromaddr,len);    fromaddr.sin_family = AF_INET;    fromaddr.sin_addr.s_addr = htonl(INADDR_ANY);    fromaddr.sin_port = htons(9000);    if((sock = socket(AF_INET,SOCK_DGRAM,0)) == -1 )    {        perror("socket create error.\n");    }        while(1)    {        alarm(5);        n = recvfrom(sock,recvbuf,1024,0,(struct sockaddr *)&fromaddr,&len);        if(n < 0)        {            if(errno == EINTR)                printf("recvfrom timeout.\n");            else                printf("recvfrom error.\n");        }        else            alarm(0);    }}

  按照上述程序运行,得到的结果如下图所示(既调用了中断函数,又终止了recvfrom函数):

  而设置为alarmact.sa_flags = SA_RESTART;选项时,结果如下图(仅调用了中断函数,却阻塞在了recvfrom上,结果与使用signal()函数效果相同):


 另:信号处理流程:若设置了信号处理函数,当信号到达时,会将控制流转向信号处理器。从信号处理器返回后,继续执行原来的控制流。

参考资料:http://liuzhigong.blog.163.com/blog/static/178272375201172021328123/

用alarm()为recvfrom设置定时器