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

时间:2011-07-25 19:47:21

标签: c++ c sockets client-server signals

一个非常标准的C ++ TCP服务器程序,使用 pthreads bind listen accept 。当我杀死连接的客户端时,我遇到了服务器结束(读取:崩溃)的情况。

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

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

signal(SIGPIPE, SIG_IGN);

因为,取自man 2 write

  

EPIPE fd 连接到读取结束的管道或插座。当发生这种情况时,写入过程也将收到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=<value optimized out>) at pthread_create.c:300
#4  ... in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#5  ... in ?? ()

3 个答案:

答案 0 :(得分:16)

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

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

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

答案 1 :(得分:12)

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

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

答案 2 :(得分:8)

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