奇怪的SIGPIPE循环

Strange SIGPIPE in loop

本文关键字:循环 SIGPIPE      更新时间:2023-10-16

在处理了我正在编写的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

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

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

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

你知道是什么原因导致的吗?

我已经摆弄了一个星期了,还是没有进展。

在我的机器上运行这个程序一次打印到标记3,正如我所期望的那样。事实上,它在你的端运行了几次,告诉我你有一个服务器监听端口25565,你没有在这个问题中包括。

你的问题是你没有测试看看服务器是否关闭了连接,你没有告诉我们。当它这样做时,您的进程获得SIGPIPE。因为你没有处理这个信号,你的进程退出。

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

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

至于为什么服务器关闭,如果不知道它是什么服务器以及它运行的是什么协议,我无法回答这个问题。不,不要在评论里回答这个问题。这与这个问题无关。简单的事实是,您正在与之通信的服务器可能随时关闭连接,您的代码必须能够处理这种情况。