#c #sockets #posix #datagram #sigpipe
#c #сокеты #posix #дейтаграмма #sigpipe
Вопрос:
Я работаю с некоторым кодом, который должен быть защищен от уничтожения вызывающего абонента из-за SIGPIPE
, но единственные выполняемые сокетом записи поступают в сокеты дейтаграмм (как UDP, так и доменные сокеты дейтаграмм Unix). Нужно ли мне беспокоиться о SIGPIPE
? Я использую connect
на сокете, но предварительное тестирование (в Linux) показало, что я просто получаю ECONNREFUSED
сообщение при отправке, если никто не прослушивает доменный сокет Unix. Не уверен, что происходит с UDP.
Я могу обернуть все это в хаки, чтобы избавиться от SIGPIPE
, но если это не проблема, я бы предпочел сэкономить на накладных расходах и снизить сложность кода.
Комментарии:
1. Я собираюсь дать вам плохой ответ. Я думаю, что я видел, как это происходило раньше при запуске приложения во время загрузки системы Linux. Я не могу сказать, был ли это определенно сокет дейтаграммы, который был основной проблемой, но, насколько я знаю, мы не использовали никаких TCP-сокетов для этого приложения. Просто тестовый пример для вас, чтобы рассмотреть, может ли это применяться к вам.
2. Я думаю, я мог бы просто организовать вещи для использования,
sendto
а неwrite
, чтобы я мог передать этот флаг, который отключаетSIGPIPE
.
Ответ №1:
Ответ содержится в спецификации для send
:
[EPIPE] Сокет закрыт для записи, или сокет находится в режиме подключения и больше не подключен. В последнем случае, и если сокет имеет тип SOCK_STREAM или SOCK_SEQPACKET и флаг MSG_NOSIGNAL не установлен, сигнал SIGPIPE генерируется в вызывающий поток.
http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html
Таким образом, нет, запись в сокеты дейтаграммы не генерирует SIGPIPE
или EPIPE
ошибку.
Комментарии:
1. Разве в приведенном выше тексте на самом деле не говорится, что вы могли получить это в UDP, если «сокет закрыт для записи» (что бы это ни значило)?
2. @T.E.D.: Возможно (если в сокете дейтаграммы работает функция выключения для записи), но это условие, которое не произошло бы без намерения программиста или ошибки. Это вызвано не одноранговым узлом.
Ответ №2:
Открытая группа — это одно, а Apple — другое. Определенно возможно получить SIGPIPE на iOS при записи в мертвый сокет UDP, как показали некоторые из моих журналов сбоев в последнее время. iOS имеет тенденцию закрывать UDP-сокеты, пока приложение работает в фоновом режиме, запись в эти сокеты может привести к появлению SIGPIPE.
Из моего журнала сбоев (любезно предоставлено testflightapp):
Исключение, последнее появление жертвы
SIGPIPE
2 libsystem_c.dylib 0x32df47ec _sigtramp 48
3 instant talk 0x0005b10e -[IPRSNetDatagramSocket send:size:to:] (iprs_iphone_net.m:671)…
Не припоминаю, чтобы это происходило в Linux, Solaris или Windows — хотя я никогда не пытался закрыть сокет, а затем записать в него.
Комментарии:
1. Закрытие сокета с последующей записью в него не даст
SIGPIPE
илиEPIPE
; это дастEBADF
. iOS, должно быть, переводит сокет в какой-то специальный нестандартный режим, чтобы вызватьSIGPIPE
. В любом случае мой вопрос был помечен как POSIX, потому что я искал стандартное поведение, но ваш ответ тоже информативен.
Ответ №3:
Согласно man 2 write
в моем окне Debian,
EPIPE: fd подключен к каналу или сокету, конец чтения которого закрыт. Когда это произойдет, процесс записи также получит сигнал SIGPIPE. (Таким образом, возвращаемое значение записи отображается, только если программа перехватывает, блокирует или игнорирует этот сигнал.)
Похоже, что возможно получить SIGPIPE при записи в сокет, но неясно, может ли это произойти конкретно для UDP-сокетов.
Комментарии:
1. Справочная страница для
send
несколько более конкретна, но она не так ясна, как то, о чем говорит POSIXsend
..2. Действительно, @R… Я поддержал ваш ответ через несколько секунд после того, как вы его опубликовали. Я просто хотел запустить процесс с моим сообщением.