如何防止SIGPIPE或阻止服务器结束?

一个非常标准的C ++ TCP服务器程序,使用pthreadsbindlistenaccept 。 我有一个场景,当我杀死连接的客户端时, 服务器结束 (读取:崩溃)。

崩溃的原因是对文件write()调用失败,因此程序收到SIGPIPE。 我猜,这会让服务器退出。

我想,“当然,未处理的信号意味着退出”,所以让我们使用signal()

 signal(SIGPIPE, SIG_IGN); 

因为,取自man 2 write

EPIPE fd连接到读取端关闭的管道或sockets。 当发生这种情况时,写入过程也将收到SIGPIPE信号。 (因此,仅当程序捕获,阻止或忽略此信号时才会看到写入返回值。)

唉,没有。 无论是在服务器线程还是客户端线程中,这似乎都没有帮助。

那么, 如何阻止write()调用引发该信号,或者(务实)如何阻止服务器退出。


我的诊断是:

  • 服务器线程启动,绑定,侦听,接受。
  • 让客户端连接(例如通过telnet)
  • 发送一个pkill telnet来崩溃客户端

不需要的行为:服务器退出,在gdb

 ... in write () at ../sysdeps/unix/syscall-template.S:82 82 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS) 

回溯

 #0 ... in write () at ../sysdeps/unix/syscall-template.S:82 #1 ... in ClientHandler::mesg(std::string) () #2 ... in ClientHandler::handle() () #3 ... in start_thread (arg=) at pthread_create.c:300 #4 ... in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112 #5 ... in ?? () 

在产生任何线程之前,你有没有机会不做signal忽略? 如果你等到一个其他线程仍然可以接收信号并退出你的应用程序。

如果不这样做,您可以在尝试写入之前始终执行写入poll / select以确保套接字是可写的。

晚会,但只是想添加到此以供将来参考:如果您在gdb中调试代码,请不要忘记它会覆盖您的信号处理程序。

因此,如果您设置了一个信号处理程序,例如:signal(SIGPIPE,SIG_IGN)并且它似乎不起作用,请尝试在调试器外部运行代码。

或者设置handle SIGPIPE nostop (在gdb提示符下)以防止gdb停止信号。

当您忽略SIGPIPE时,您不再获得SIGPIPE信号,但write()会收到EPIPE错误。