首页 新闻 会员 周边

帮忙分析一个问题。select与SIGALRM信号冲突,想知道原因。环境suse11

0
悬赏园豆:100 [已解决问题] 解决于 2013-08-06 14:07
 1 #include <unistd.h> 
 2 #include<stdio.h>
 3 #include <signal.h>
 4 #include <sys/time.h>
 5 #include <sys/socket.h>
 6 #include <fcntl.h>
 7 #include <arpa/inet.h>
 8 #include <string.h>
 9 
10 typedef int                 TINTEGER;
11 
12 TINTEGER        g_fdSocket;                // Socket句柄
13 struct sockaddr_in  g_localAddr;           // 本端地址
14 
15     
16 void ALARMProc(int isig)
17 {
18     printf("12345678219\n");
19 }
20 
21 int main()
22 {
23         sigset(SIGALRM, ALARMProc);
24         
25         struct timeval  timenext;
26         struct timeval  timeinterval;
27         timenext.tv_sec = 10;
28         timenext.tv_usec = 0;
29         timeinterval.tv_sec = 10;
30         timeinterval.tv_usec = 0;
31         
32         struct itimerval value;
33         value.it_interval = timenext;
34         value.it_value = timeinterval;
35         
36         setitimer(ITIMER_REAL , &value, NULL);
37 
38         const char* pManagerIP = "0.0.0.0";
39         int iPort = 56489;
40         // 创建套接字
41         g_fdSocket = socket(AF_INET, SOCK_STREAM, 0);
42         // 设置端口属性为非阻塞
43         fcntl(g_fdSocket, F_SETFL, fcntl(g_fdSocket, F_GETFL) | O_NONBLOCK);
44         // 设置端口句柄不可被子进程继承
45         fcntl(g_fdSocket, F_SETFD, 1);
46         // 设置可复用端口
47         int iReuseAddrFlag=1;
48         int iSetResult;
49         // 设置终端信息
50         setsockopt(g_fdSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&iReuseAddrFlag, sizeof(iReuseAddrFlag));     
51         g_localAddr.sin_family = AF_INET;
52         g_localAddr.sin_addr.s_addr = inet_addr(pManagerIP);  
53         g_localAddr.sin_port = htons(iPort);
54         // 绑定套接字 
55         bind(g_fdSocket, (struct sockaddr *)&g_localAddr, sizeof(g_localAddr));
56         // 侦听端口
57         listen(g_fdSocket, 5);
58       
59       while(1)
60       {
61               // 阻塞方式等待指定时间,检查是否有新的连接接入
62               fd_set rset;
63               FD_ZERO(&rset);
64               FD_SET(g_fdSocket, &rset);
65             //设置接收连接超时时间
66               struct timeval waitTime;
67             waitTime.tv_sec  = 1;
68             waitTime.tv_usec = 0;
69             select(g_fdSocket + 1, &rset, NULL, NULL, &waitTime);
70             if (FD_ISSET(g_fdSocket, &rset))
71             {
72                     int fd = 0;        //接受客户端连接的socket
73                     struct sockaddr_in inClientAddr; //用于存放对端的地址
74                     memset(&inClientAddr, 0, sizeof(inClientAddr));
75                     socklen_t iLen = sizeof(struct sockaddr_in);
76                     fd = accept(g_fdSocket, (struct sockaddr *)(&inClientAddr),(socklen_t*) &iLen);
77                     if (fd < 0)
78                     {
79                             printf("accept connect failed\n");
80                             continue;
81                     }
82                     char* pLinkIP = inet_ntoa(inClientAddr.sin_addr);
83                     int iLinkPort = ntohs(inClientAddr.sin_port);
84                     
85                     printf("accept client ip %s, port %d\n", pLinkIP, iLinkPort);    
86             }
87             printf("no connect\n");
88       }
89    //while(1)    
90    //{        
91    //   printf("+\n");        
92    //   sleep(1);    
93    //};
94    return 0;
95 }

这段代码运行,按照预期是每隔十个"no connect",输出一个"12345678219"。但实际运行过程中却发现竟然会在输出"12345678219"的同时,输出"accept connect failed"。求大神告知原因

BLoodMaster的主页 BLoodMaster | 初学一级 | 园豆:135
提问于:2013-01-22 15:29
< >
分享
最佳答案
0

问题搞明白了。SELECT自身也是通过SIGALRM信号来唤醒自身的。一般情况下,如果是SGALARM唤醒的话,是因为超时时间到,这种情形,fd就不会被加到fd_set中。但是假如程序里面别的地方定义了setimer的话,setimer也会定时触发SIGALRM信号至目标进程,导致被SELECT阻塞的地方被唤醒,但此时却没达到超时时间,故而被当做以为目标句柄fd发生了变化,更改为ready,此时fd被无情的添加到了FD_SET中,故而进入了分支判断。当然实际上fd被没用发生状态变化,故而accept失败,打出了那个失败的日志。

BLoodMaster | 初学一级 |园豆:135 | 2013-01-22 17:06

上面分析错了。刚才我把信号都试验了下。SIGALARM与SIGVLARM信号并没有唤醒SELECT。倒是kill -15唤醒了select,而且存在一定的偶然性。迷茫中,看来settimer与select的底层都不是简单的什么SIGALRM信号搞定的。谁知道答案的,求指教

BLoodMaster | 园豆:135 (初学一级) | 2013-01-23 14:20
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册