【发布时间】:2013-10-30 19:41:23
【问题描述】:
我正在开发一个通过 TCP 连接到服务器的应用程序。
如果套接字由于某种原因被关闭,我最终会进入 SIGPIPE 处理程序。
我该怎么做才能使 recv 和 send 只在断开/关闭的套接字上返回错误?
谢谢
【问题讨论】:
-
我读过这篇文章,但那篇文章似乎没有解决我遇到的问题。我可能做错了什么。
标签: c xcode macos sockets sigpipe
我正在开发一个通过 TCP 连接到服务器的应用程序。
如果套接字由于某种原因被关闭,我最终会进入 SIGPIPE 处理程序。
我该怎么做才能使 recv 和 send 只在断开/关闭的套接字上返回错误?
谢谢
【问题讨论】:
标签: c xcode macos sockets sigpipe
SIG_IGN 信号而不是处理它。 send 将返回 -1 并且 errno 将设置为 EPIPE。
【讨论】:
read() 和 recv() 返回 0 如果对等方关闭或关闭连接。有关详细信息,请参阅 man read 或 man recv。如果仍然不清楚,请就这个不同的主题提出另一个问题。
signal 系统调用语义跨平台是非标准的。在 linux 上,您可以通过功能测试宏来哄它按照您想要的方式运行,但我不知道 OSX 的默认设置。最好使用sigaction,我看到alk 留下了一个描述如何做到这一点的答案。
使用信号处理程序或忽略它
#include <signal.h>
signal(SIGPIPE, SIG_IGN);
在写入套接字时,首先检查套接字 fd 是否为正或不在程序中。在外部,您应该检查您是否正在发送有效套接字的指针
【讨论】:
signal(),您很可能需要在使用一次后重新应用处理程序。不要使用signal使用sigaction()`。
你可以忽略SIGPIPE
#include <signal.h>
signal(SIGPIPE, SIG_IGN);
或者您可以使用信号处理程序。
signal(SIGPIPE, handler);
void handler(int signal)
{
//("Signal caught");
}
【讨论】:
printf(),因为不能保证printf() 是信号安全的。
要忽略信号,请将信号处理程序设置为 SIG_IGN 这样做:
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN;
if (-1 == sigaction(SIGPIPE, &sa, NULL))
{
perror("sigaction() failed");
}
【讨论】:
我发现忽略 SIGPIPE 在 OS X 上无效。请改用 SO_NOSIGPIPE。请注意,这是在套接字上设置一次,而不是在每次调用 send() 时请求的 MSG_NOSIGNAL。
int socket = accept (...); /* (or however you're getting the socket) */
int option_value = 1; /* Set NOSIGPIPE to ON */
if (setsockopt (socket, SOL_SOCKET, SO_NOSIGPIPE, &option_value, sizeof (option_value)) < 0) {
perror ("setsockopt(,,SO_NOSIGPIPE)");
}
【讨论】:
忽略 SIGPIPE,如其他答案中所述(即signal(SIGPIPE, SIG_IGN);)在 OS X 上对我有用。另外,请务必在调试器之外进行测试,如this comment 中所述。我正在使用lldb 进行调试,它的信号处理正在使用 SIGPIPE 终止我的程序,即使我忽略了该信号。在lldb 之外的测试工作正常。
【讨论】: