为什么recvfrom()在捕获SIGALRM时仍会阻塞?

时间:2016-06-18 07:39:18

标签: c linux unix networking network-programming

我想使用alarm()来设置recvfrom的超时时间。但是发现当使用signal()注册SIGALRM的处理程序时,已经捕获了SIGALRM,然后调用了信号处理程序。但是从处理程序返回后,recvfrom()仍然阻塞,而没有数据到来,并且没有EINTR错误。为什么? signal()是否自动设置SA_RESTART标志? 这是代码:

signal(SIGALRM, sig_handler);
while(1)
{
    alarm(5);
    n = recvfrom(sock, buf, BUF_MAX, 0, (struct sockaddr*)&addr, &len);
    if(n < 0)
    {
        if(errno == EINTR)
        {
            printf("recvfrom timeout\n");
            continue;
        }
        else
        {
            printf("recvfrom error\n");
        }
    }
    else
    {
         printf("data: %s\n", buf);
         alarm(0);
    }
}

void sig_handler(int signo)
{
    return;
}

1 个答案:

答案 0 :(得分:1)

根据signal的手册页,

是否重新启动阻止调用是依赖于平台的属性:

  

Linux的情况如下:

     
      
  • 内核的signal()系统调用提供了System V语义。
  •   
  • 默认情况下,在glibc 2及更高版本中,signal()包装函数不会调用内核系统调用。相反,它使用提供BSD的标志调用sigaction(2)        语义。只要定义了合适的功能测试宏,就会提供此默认行为:glibc 2.19及更早版本的_BSD_SOURCE或_DEFAULT_SOURCE        glibc 2.19及更高版本。 (默认情况下,定义了这些宏;有关详细信息,请参阅feature_test_macros(7)。)如果未定义此类功能测试宏,则signal()        提供System V语义。
  •   

由于BSD语义等同于使用以下标志调用sigaction(2)

sa.sa_flags = SA_RESTART;

和System V语义没有SA_RESTART,你看到的是你的程序正在以BSD方式运行,因此你应该确保使用所述的功能测试宏来获得程序的定义行为。