c - 为什么在捕获 SIGALRM 后 recvfrom() 仍然阻塞?

标签 c linux unix networking network-programming

我想使用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;
}

最佳答案

根据 signal 的手册页,是否重新启动阻塞调用是一个依赖于平台的属性:

The situation on Linux is as follows:

  • The kernel's signal() system call provides System V semantics.
  • By default, in glibc 2 and later, the signal() wrapper function does not invoke the kernel system call. Instead, it calls sigaction(2) using flags that supply BSD semantics. This default behavior is provided as long as a suitable feature test macro is defined: _BSD_SOURCE on glibc 2.19 and earlier or _DEFAULT_SOURCE in glibc 2.19 and later. (By default, these macros are defined; see feature_test_macros(7) for details.) If such a feature test macro is not defined, then signal() provides System V semantics.

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

sa.sa_flags = SA_RESTART;

并且 System V 语义不执行 SA_RESTART,您所看到的是您的程序正在执行 BSD 方式,因此您应该确保使用上述功能测试宏来获取程序的定义行为.

关于c - 为什么在捕获 SIGALRM 后 recvfrom() 仍然阻塞?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37894535/

相关文章:

c - GDB 跳过共享库断点

c++ - 以附加模式打开管道

linux - 更改intel parallel Studio 2018安装目录

linux - 如果文件 2 中包含的行带有前缀,如何从文件 2 中删除文件 1 中包含的行?

jsp - 在 Unix 中通过 tomcat 托管的 jsp 页面中获取远程(客户端)用户名

c - Linux 命令真的是 C 目标文件吗?

c - C中管道的实现

c - 是否有一种方式可以一点一点地修改 vector/数组的元素?

c - 两个UDP监听器中只有一个接收消息

c - 在C中将直接字符串分配给char数组