【问题标题】:why recvfrom() still block when a SIGALRM has been captured?为什么当 SIGALRM 被捕获时 recvfrom() 仍然阻塞?
【发布时间】:2016-10-20 01:22:16
【问题描述】:

我想用alarm()来设置recvfrom的超时时间。但是发现当使用signal()SIGALRM注册一个handler时,一个SIGALRM已经被捕获,然后调用了signal handler。但是从处理程序返回后,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;
}

【问题讨论】:

  • 真正的问题是你为什么不使用 SO_RCVTIMEO?

标签: c linux unix networking network-programming


【解决方案1】:

阻塞调用是否重启是平台相关属性,根据signal的man page:

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 方式,因此您应该确保使用所述功能测试宏来获得程序的定义行为。

【讨论】:

    猜你喜欢
    • 2012-10-31
    • 1970-01-01
    • 2015-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-24
    • 1970-01-01
    • 2017-04-26
    相关资源
    最近更新 更多