Как предотвратить SIGPIPE или запретить завершение работы сервера? - PullRequest
18 голосов
/ 25 июля 2011

Совершенно стандартная программа на 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 ]

16 голосов
/ 04 октября 2011

Поздно на вечеринке, но просто хотел добавить это для дальнейшего использования: если вы отлаживаете свой код в gdb, не забывайте, что он переопределяет ваши обработчики сигналов.

Так что если вы установилиобработчик сигнала, такой как: signal (SIGPIPE, SIG_IGN), и он, кажется, не работает, попробуйте запустить код вне отладчика.

или установите handle SIGPIPE nostop (в приглашении gdb), чтобы предотвратить остановку gdbпо сигналу.

12 голосов
/ 26 июля 2011

Вы случайно не игнорировали signal до появления каких-либо потоков?Если вы подождете до тех пор, пока один из других потоков не сможет принять сигнал и выйти из вашего приложения.

Если этого не произойдет, вы всегда можете сделать запись poll / select перед попыткойзапись, чтобы убедиться, что сокет доступен для записи.

9 голосов
/ 25 июля 2011

Когда вы игнорируете SIGPIPE, вы больше не получаете сигнал SIGPIPE, но write() получает ошибку EPIPE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...