4

我正在为 Linux 上的 TCP 连接编写 C++ SSL 服务器。当程序用于SSL_write()写入封闭管道时,会抛出 SIGPIPE-Exception 导致程序关闭。我知道这是正常行为。但是当对等方没有正确关闭连接时,程序不应该总是死掉。

我已经用谷歌搜索了很多东西,并且尝试了几乎所有我发现的东西,但似乎没有什么对我有用。signal(SIGPIPE,SIG_IGN)不起作用 - 仍然会抛出异常(对于signal(SIGPIPE, SomeKindOfHandler).

gdb 输出:

Program received signal SIGPIPE, Broken pipe.
0x00007ffff6b23ccd in write () from /lib/x86_64-linux-gnu/libpthread.so.0
(gdb) where
#0  0x00007ffff6b23ccd in write () from /lib/x86_64-linux-gnu/libpthread.so.0
#1  0x00007ffff7883835 in ?? () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#2  0x00007ffff7881687 in BIO_write () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#3  0x00007ffff7b9d3e0 in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.0.0
#4  0x00007ffff7b9db04 in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.0.0
#5  0x000000000042266a in NetInterface::SendToSubscribers(bool) () at ../Bether/NetInterface.h:181
#6  0x0000000000425834 in main () at ../Bether/main.cpp:111

关于代码:

我正在使用一个正在等待新连接并接受它们的线程。然后线程将连接信息(BIO 和 SSL)放入NetInterface类内的静态映射中。每 5 秒NetInterface::sendTOSubscribers()从 执行一次main()。此函数访问静态映射并将数据发送到其中的每个连接。这个函数也是 SIGPIPE 的来源。我已经使用signal(SIGPIPE,SIG_IGN)in main()(显然是在 5 秒循环之前)和 in NetInterface::SendToSubscribers(),但它在任何地方都不起作用。

谢谢你的帮助!

4

2 回答 2

4

您必须调用函数 sigaction 来更改此行为以忽略 SIGPIPE 或使用您自己的信号处理程序以特定方式处理它。请不要使用函数信号,它已经过时了。

http://man7.org/linux/man-pages/man2/sigaction.2.html

一种方法(我没有编译这段代码,但应该是这样的):

void sigpipe_handler(int signal)
{
   ...
}

int main() 
{
    struct sigaction sh;
    struct sigaction osh;

    sh.sa_handler = &sigpipe_handler; //Can set to SIG_IGN
    // Restart interrupted system calls
    sh.sa_flags = SA_RESTART;

    // Block every signal during the handler
    sigemptyset(&sh.sa_mask);

    if (sigaction(SIGPIPE, &sh, &osh) < 0)
    {
        return -1;
    }

    ...
}

如果程序是多线程的,则有点不同,因为您对哪个线程将接收信号的控制较少。这取决于信号的类型。对于 SIGPIPE,它将被发送到生成信号的 pthread。尽管如此, sigaction 应该可以正常工作。

可以在主线程中设置掩码,随后创建的所有 pthread 都将继承信号掩码。否则,可以在每个线程中设置信号掩码。

sigset_t blockedSignal; 
sigemptyset(&blockedSignal);    
sigaddset(&blockedSignal, SIGPIPE); 
pthread_sigmask(SIG_BLOCK, &blockedSignal, NULL);

但是,如果您阻止该信号,它将等待该过程,并尽快将其交付。对于这种情况,请在线程结束时使用 sigtimedwait。在主线程或生成 SIGPIPE 的线程中设置的 sigaction 也应该可以工作。

于 2015-08-17T00:13:46.780 回答
1

我找到了解决方案,它适用于 pthread_sigmask。

sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGPIPE);
if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
    return -1;

感谢大家的帮助!

于 2015-08-17T16:09:55.710 回答