用alarm()爲recvfrom設置定時器

轉載自:https://www.cnblogs.com/dreamrun/p/4047795.html

  因爲項目需要,需要以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()函數效果相同):

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章