用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/

浙公網安備 33010602011771號