SIGPIPE (OSX) и отключенные сокеты?

Я работаю над приложением, которое подключается к серверу через TCP.

Если сокет по какой-либо причине закрыт, я попадаю в обработчик SIGPIPE.

Что мне сделать, чтобы recv и send просто возвращали ошибку на отключенном / закрытом сокете?

Спасибо


person user1884325    schedule 22.10.2013    source источник
comment
возможный дубликат Как предотвратить SIGPIPE (или обработать их должным образом)   -  person Martin R    schedule 22.10.2013
comment
Я прочитал этот пост, но, похоже, ничто в нем не решает мою проблему. Я наверное что-то не так делаю.   -  person user1884325    schedule 22.10.2013


Ответы (6)


Я обнаружил, что игнорирование SIGPIPE неэффективно в OS X. Вместо этого используйте SO_NOSIGPIPE. Обратите внимание, что это устанавливается в сокете один раз, в отличие от MSG_NOSIGNAL, который запрашивается при каждом вызове send ().

int socket = accept (...); /* (or however you're getting the socket) */
int option_value = 1; /* Set NOSIGPIPE to ON */
if (setsockopt (socket, SOL_SOCKET, SO_NOSIGPIPE, &option_value, sizeof (option_value)) < 0) {
    perror ("setsockopt(,,SO_NOSIGPIPE)");
}
person Perette    schedule 26.04.2016

SIG_IGN сигнал, а не его обработка. send вернет -1, а errno будет установлено значение EPIPE.

person Duck    schedule 22.10.2013
comment
А как насчет recv? Этот - ›сигнал (SIGPIPE, SIG_IGN), похоже, не помогает. Я все еще получаю SIGPIPE. Полагаю, recv просто блокируется, пока сокет не будет закрыт? Что вернет recv, если соединение разорвано по какой-либо причине? Всего 0? - person user1884325; 22.10.2013
comment
read() и recv() возвращают 0, если партнер закрыл или прервал соединение. Подробнее см. man read или man recv. Если все еще неясно, задайте еще один вопрос по этой другой теме. - person alk; 22.10.2013
comment
Как сказал алк, вам не нужно беспокоиться о сигпайпе с recv. Если одноранговый узел сокета закрыт, вы получите обычное уведомление о завершении работы с нулевым чтением. Семантика системных вызовов signal нестандартна для разных платформ. В Linux вы можете уговорить его вести себя так, как вы хотите, с помощью макросов тестирования функций, но я не знаю, какие настройки OSX установлены по умолчанию. Лучше использовать sigaction, и я вижу, что alk оставил ответ, описывающий, как это сделать. - person Duck; 22.10.2013

Чтобы игнорировать сигнал, установите для обработчика сигнала значение SIG_IGN, выполнив следующие действия:

struct sigaction sa;
memset(&sa, 0, sizeof(sa));

sa.sa_handler = SIG_IGN;

if (-1 == sigaction(SIGPIPE, &sa, NULL))
{
  perror("sigaction() failed");
}
person alk    schedule 22.10.2013

Игнорирование SIGPIPE, как описано в других ответах (например, signal(SIGPIPE, SIG_IGN);), сработало для меня в OS X. Также не забудьте протестировать вне отладчика, как говорится в этот комментарий. Я выполнял отладку с помощью lldb, и его обработка сигналов завершала мою программу с помощью SIGPIPE, хотя я проигнорировал этот сигнал. Тестирование вне lldb прошло нормально.

person user2683747    schedule 07.05.2017

Вы можете игнорировать SIGPIPE

 #include <signal.h>

signal(SIGPIPE, SIG_IGN);

Или вы можете использовать обработчик сигналов.

signal(SIGPIPE, handler);
void handler(int signal)
{   
    //("Signal caught");

}
person Parag Bafna    schedule 22.10.2013
comment
Не printf() из обработчиков signl, поскольку printf() не гарантирует безопасность сигналов. - person alk; 22.10.2013
comment
@alk Спасибо. Обновлено. - person Parag Bafna; 22.10.2013

использовать обработчик сигнала или игнорировать его

#include <signal.h>
signal(SIGPIPE, SIG_IGN);

при записи в сокет сначала проверьте, положительный ли fd сокета в программе. Внешне вы должны проверить, что вы отправляете указатель действительного сокета.

person Gaurav    schedule 22.10.2013
comment
вы использовали #include ‹signal.h› ?? - person Gaurav; 22.10.2013
comment
@ user1884325: при использовании signal() вам, скорее всего, потребуется повторно применить обработчик после того, как он был однажды использован. Не используйте signal use sigaction () `. - person alk; 22.10.2013
comment
да, sigaction более наглядный и полезный, но POSIX.1 и сигнал являются базовыми, но это особенность ISO C - person Gaurav; 22.10.2013