这是我的服务器端代码(部分)
void timeout_handler(int value) {
printf("Handler\n");
return;
}
int main (int argc, char **argv) {
[...]
signal(SIGALRM, timeout_handler);
alarm(seconds);
int result = read(input_socket, buffer, sizeof(buffer));
if (result == -1 && errno == EINTR) {
printf("read() failed\n");
}
[...]
}
其中input_socket
是与客户端正确连接的TCP套接字(如果我从客户端发送数据,服务器会收到它们)。
作为对警报信号的测试,我试图打开并连接套接字客户端而不发送任何数据。 我希望输出像
Handler
read() failed
但结果只是Handler
消息,然后该过程仍处于活动状态。
为什么read()
不会因errno=EINTR
而失败?
答案 0 :(得分:1)
同样在OSX上,当信号中断时,某些系统调用默认重启。
siginterrupt()
可用于更改此行为。以下行(调用alarm()
之前的某个地方)应该完成这项工作,让程序按照OP的预期运行:
siginterrupt(SIGALRM, 1);
从OSX文档(我强调):
对于某些系统调用,如果在执行调用时捕获到信号并且过早地进行调用 终止后,呼叫会自动重启。 使用signal(3)安装的任何处理程序都将具有 SA_RESTART标志设置,这意味着任何可重新启动的系统调用都不会在收到信号时返回。 受影响的系统调用包括 read(2),write(2),sendto(2),recvfrom(2),sendmsg(2)和recvmsg(2) 在通信信道或低速设备上以及在ioctl(2)或等待(2)期间。但是,电话 已经提交的内容未重新启动,而是返回部分成功(例如,a 短读数)。可以使用siginterrupt(3)更改这些语义。
这在Linux上是不同的,例如,发送信号需要明确地请求重新启动系统调用。