一个非常标准的C ++ TCP服务器程序,使用 pthreads , bind , listen 和 accept 。当我杀死连接的客户端时,我遇到了服务器结束(读取:崩溃)的情况。
崩溃的原因是文件上的write()
调用失败,因此程序收到SIGPIPE。我想,这会让服务器退出。
我想,“当然,未处理的信号意味着退出”,所以让我们使用signal()
:
signal(SIGPIPE, SIG_IGN);
因为,取自man 2 write
:
唉,不,不。无论是在服务器线程还是客户端线程中,这似乎都没有帮助。EPIPE fd 连接到读取结束的管道或插座。当发生这种情况时,写入过程也将收到SIGPIPE信号。 (因此,仅当程序捕获,阻止或忽略此信号时才会看到写返回值。)
所以,如何阻止write()
调用提升该信号,或者(务实)如何阻止服务器退出。
我的诊断是:
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 ?? ()
答案 0 :(得分:16)
晚会,但只是想添加到此以供将来参考: 如果您在gdb中调试代码,请不要忘记它会覆盖您的信号处理程序。
因此,如果您设置了一个信号处理程序,例如:signal(SIGPIPE,SIG_IGN)并且它似乎不起作用,请尝试在调试器外部运行代码。
或设置handle SIGPIPE nostop
(在gdb提示符下)以防止gdb停止信号。
答案 1 :(得分:12)
在产生任何线程之前,您是否有机会不执行signal
忽略?如果你等到一个其他线程仍然可以接收信号并退出你的应用程序。
如果没有这样做,你可以在尝试写入之前始终执行写poll
/ select
以确保套接字是可写的。
答案 2 :(得分:8)
当您忽略SIGPIPE时,您不再收到SIGPIPE信号,但write()
会收到EPIPE
错误。