C ++& OpenSSL:在封闭管道中写入时的SIGPIPE

时间:2015-08-16 23:01:07

标签: c++ linux openssl sigpipe

我在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()执行signal(SIGPIPE,SIG_IGN)。此函数访问静态映射并将数据发送到其中的每个连接。此功能也是SIGPIPE的来源。 我在main()(显然在5秒循环之前)和NetInterface::SendToSubscribers()中使用了{{1}},但它在任何地方都无法使用。

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

您必须调用函数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也应该起作用。

答案 1 :(得分:0)

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

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

感谢大家的帮助!