循环中的奇怪的SIGPIPE

时间:2016-06-30 16:21:44

标签: c++ unix signals system-calls

在处理我写的C ++程序中的一个非常奇怪的错误之后,我决定写下面的测试代码,证实了我的怀疑。在原始程序中,在循环中调用send()this_thread::sleep_for()(任意时间)16次会导致发送失败并显示SIGPIPE信号。然而,在这个例子中,它在4次后失败。

我在端口25565上运行的服务器绑定到localhost。原始程序旨在与此服务器通信。我在此测试代码中使用相同的代码,因为它不会提前终止连接。

int main()
{
        struct sockaddr_in sa;
        memset(sa.sin_zero, 0, 8);
        sa.sin_family = AF_INET;
        inet_pton(AF_INET, "127.0.0.1", &(sa.sin_addr));
        sa.sin_port = htons(25565);

        cout << "mark 1" << endl;

        int sock = socket(AF_INET, SOCK_STREAM, 0);
        connect(sock, (struct sockaddr *) &sa, sizeof(sa));

        cout << "mark 2" << endl;

        for (int i = 0; i < 16; i++)
        {
                cout << "mark 3" << endl;
                cout << "sent " << send(sock, &i, 1, 0) << " byte" << endl;
                cout << "errno == " << errno << endl;
                cout << "i == " << i << endl;
                this_thread::sleep_for(chrono::milliseconds(2));
        }

        return 0;
}

在GDB中运行它是我发现它发出SIGPIPE的方式。以下是输出:http://pastebin.com/gXg2Y6g1

在另一个测试中,我在循环中调用this_thread::sleep_for() 16次,然后调用send()一次。这没有产生相同的错误。它没有问题。

在另一个测试中,我注释掉了线程的睡眠线,它一直运行得很好。我在原始程序和上面的测试代码中都这样做了。

这些结果让我相信这不是服务器关闭连接的情况,即使这通常是SIGPIPE的意思(为什么没有调用this_thread::sleep_for()时它运行良好?)。

关于可能导致这种情况的任何想法?我已经搞乱了一个星期而已经没有了。

1 个答案:

答案 0 :(得分:0)

在我的机器上运行此程序,打印到标记3,就像我预期的那样。事实上,它确实在您的端部运行了几次,这告诉我您有一个服务器正在侦听端口25565,您没有将其包含在此问题中。

您的问题是您没有进行测试,看看您没有告诉我们的服务器是否关闭了连接。如果是这样,您的流程将获得SIGPIPE。由于您没有处理该信号,因此您的流程退出。

你可以做些什么来解决这个问题:

  1. 开始检查函数的返回值。在这种特定情况下,它没有帮助,但您忽略connectsend的潜在错误。我希望这是因为最小化程序,但值得一提。
  2. 处理信号。如果您希望从代码的主流处理服务器关闭,则可以注册忽略信号的处理程序,或将标记MSG_NOSIGNAL传递给send。在这两种情况下,在-1设置为errno的情况下,send会返回EPIPE
  3. RTFM。认真。一个简单的man send和一个SIGPIPE的搜索会给你这个答案。
  4. 至于服务器关闭的原因,我不知道在不知道它是什么服务器以及它运行的协议的情况下回答这个问题。不,不要在评论中回答这个问题。这与这个问题无关。事情的简单事实是,您正在与之交谈的服务器可能随时关闭连接,并且您的代码必须能够处理该连接。

相关问题