Сокет: постоянно получая POLLHUP на полузакрытых
Я написал сервер сокетов, работающий на Linux, но это, вероятно, не спецификация Linux.
я использую poll()
проверить состояние клиентов. Мои клиенты делают активное (наполовину) закрытие после отправки запроса. Сервер постоянно попадает POLLHUP
а также POLLERR
из-за полузакрытого клиента. Я тоже вижу POLLRDHUP
, так что я знаю, что на самом деле это полузакрытие, а не соединение / сброс соединения Моя проблема в том, что я всегда получаю эти события, хотя я уже знал из предыдущего опроса, что была половина закрытия.
Как я могу отключить это, чтобы я больше не получал это событие? Я пытался сделать дополнительные read()
и сделать shutdown(fd, SHUT_RD)
, но это, похоже, не помогает. Я не хочу poll
чтобы проснуться для события, которое я уже обработал.
2 ответа
Прекратите включать fd в набор readfds, как только вы наполовину закроете. Больше нечего читать, кроме полузакрытия. С этой точки зрения единственное, что вас может заинтересовать - это "доступные для записи" события.
Просто не обращай внимания POLLHUP
в ответ флаги. Существующий код, если он правильный, будет делать то, что вы хотите.
Тот факт, что вы будете получать полузакрытые poll()
(обрисовано в общих чертах ответом EJP) - это особенность, а не ошибка. Это позволяет вам обращаться с полузакрытыми точно так же, как конец файла; это именно то, что вы хотите, так как оно позволяет вашему приложению читать последние байты в буфере сокета, а не отбрасывать их (что является правильной семантикой полузакрытия TCP).
Как только "обычный" конец файла достигнут, poll()
всегда будет выбирать файловый дескриптор как готовый для чтения. Петля вокруг poll()
Затем предполагается read()
данные до конца файла видны, а затем close()
, Игнорирование POLLHUP
условие позволяет вашей программе делать то же самое с одним и тем же кодом в полузакрытых ситуациях и получать последние байты в буфере сокета.
Кроме того, вы должны реализовать поток управления, не заботясь о POLLHUP
, Если (и только если) вам нужно ограничить дескриптор файла (то есть в настоящее время некуда поставить read()
байт в), затем удалите этот дескриптор из poll()
установить, чтобы ядро не давало вам готовые к чтению "прерывания", пока вы не скажете это снова (без регулирования). Тот факт, что все данные уже находятся в буфере сокета (что является POLLHUP
бит указывает) опять не имеет значения.