【问题标题】:Strange SIGPIPE in loop奇怪的 SIGPIPE 循环
【发布时间】:2016-06-30 16:21:44
【问题描述】:

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

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

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

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

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

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

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

【问题讨论】:

    标签: c++ unix signals system-calls


    【解决方案1】:

    在我的机器上运行它会打印一次标记 3,正如我所期望的那样。它确实在您端运行了几次这一事实告诉我,您有一台服务器正在侦听端口 25565,而您尚未将其包含在此问题中。

    您的问题是您没有测试您没有告诉我们的服务器是否关闭了连接。当它发生时,您的进程会得到一个SIGPIPE。由于您不处理该信号,因此您的进程将退出。

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

    1. 开始检查函数的返回值。在这种特殊情况下它不会有帮助,但是您忽略了来自connectsend 的潜在错误。我希望这是因为最小化程序,但值得一提。
    2. 处理信号。如果您更喜欢从代码的主要流程处理服务器关闭,您可以注册一个忽略信号的处理程序,或者将标志 MSG_NOSIGNAL 传递给 send。在这两种情况下,发送都将返回 -1,在这种情况下,errno 设置为 EPIPE
    3. RTFM。严重地。一个简单的man send 和搜索SIGPIPE 会给你这个答案。

    至于服务器关闭的原因,在不知道它是什么服务器以及它正在运行什么协议的情况下,我无法回答这个问题。不,不要在 cmets 中回答这个问题。与这个问题无关。简单的事实是,您正在与之交谈的服务器可能随时关闭连接,您的代码必须能够处理这种情况。

    【讨论】:

      猜你喜欢
      • 2019-08-05
      • 2017-08-20
      • 1970-01-01
      • 2019-02-11
      • 2019-04-30
      • 2017-04-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多