C++ 和 OpenSSL:在封闭管道中写入时的 SIGPIPE
C++ & OpenSSL: SIGPIPE when writing in closed pipe
我正在为 Linux 上的 TCP 连接编写 C++ SSL 服务器。
当程序使用 SSL_write()
写入关闭的管道时,会抛出 SIGPIPE 异常,导致程序关闭。我知道这是正常行为。但是当对等方没有正确关闭连接时,程序不应该总是死掉。
我已经在谷歌上搜索了很多,并尝试了几乎所有我找到的东西,但似乎没有任何东西适合我。 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
class 内的静态映射中。
每 5 秒 NetInterface::sendTOSubscribers()
从 main()
开始执行。此函数访问静态映射并将数据发送到其中的每个连接。这个函数也是 SIGPIPE 的来源。
我在 main()
(显然在 5 秒循环之前)和 NetInterface::SendToSubscribers()
中使用了 signal(SIGPIPE,SIG_IGN)
,但它在任何地方都不起作用。
感谢您的帮助!
您必须调用函数 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 应该可以正常工作。
可以在主线程中设置掩码,所有后续创建的pthreads都将继承信号掩码。否则,可以在每个线程中设置信号掩码。
sigset_t blockedSignal;
sigemptyset(&blockedSignal);
sigaddset(&blockedSignal, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &blockedSignal, NULL);
但是,如果您阻止信号,它将等待处理,并会尽快交付。对于这种情况,请在线程末尾使用 sigtimedwait。在主线程或生成 SIGPIPE 的线程中设置的 sigaction 也应该有效。
我找到了解决方案,它适用于 pthread_sigmask。
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGPIPE);
if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
return -1;
感谢大家的帮助!
我正在为 Linux 上的 TCP 连接编写 C++ SSL 服务器。
当程序使用 SSL_write()
写入关闭的管道时,会抛出 SIGPIPE 异常,导致程序关闭。我知道这是正常行为。但是当对等方没有正确关闭连接时,程序不应该总是死掉。
我已经在谷歌上搜索了很多,并尝试了几乎所有我找到的东西,但似乎没有任何东西适合我。 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
class 内的静态映射中。
每 5 秒 NetInterface::sendTOSubscribers()
从 main()
开始执行。此函数访问静态映射并将数据发送到其中的每个连接。这个函数也是 SIGPIPE 的来源。
我在 main()
(显然在 5 秒循环之前)和 NetInterface::SendToSubscribers()
中使用了 signal(SIGPIPE,SIG_IGN)
,但它在任何地方都不起作用。
感谢您的帮助!
您必须调用函数 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 应该可以正常工作。
可以在主线程中设置掩码,所有后续创建的pthreads都将继承信号掩码。否则,可以在每个线程中设置信号掩码。
sigset_t blockedSignal;
sigemptyset(&blockedSignal);
sigaddset(&blockedSignal, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &blockedSignal, NULL);
但是,如果您阻止信号,它将等待处理,并会尽快交付。对于这种情况,请在线程末尾使用 sigtimedwait。在主线程或生成 SIGPIPE 的线程中设置的 sigaction 也应该有效。
我找到了解决方案,它适用于 pthread_sigmask。
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGPIPE);
if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
return -1;
感谢大家的帮助!