Epoll и дистанционное одностороннее отключение - PullRequest
11 голосов
/ 03 января 2012

Предположим, что сокет TCP на локальном хосте Linux находится в состоянии соединения с удаленным хостом.Локальный хост использует epoll_wait для уведомления о событиях в сокете с удаленным хостом.

Если удаленный хост должен был позвонить:

 shutdown(s,SHUT_WR);

на своем подключенном сокете, чтобы указать, что этопередача завершена, какие события будут возвращаться epoll_wait на локальном хосте для своего сокета?

Я предполагаю, что EPOLLIN всегда будет возвращаться, а последующий вызов recv вернет 0, чтобы указать, что удаленная сторона завершила передачу.

А как насчет EPOLLHUP или EPOLLRDHUP?(И в чем разница между этими двумя событиями)?

Или даже EPOLLERR?

Если удаленный хост вызывает «close» вместо «shutdown», изменится ли ответ на любой из вышеперечисленных вопросов?

1 Ответ

20 голосов
/ 07 января 2012

Я отвечаю на это сам после выполнения тяжелой работы, чтобы найти ответ.

Сокет, прослушивающий события epoll, обычно получает флаг события EPOLLRDHUP (в дополнение к EPOLLIN) при удаленном одноранговом соединении, вызывающем закрытие или отключение (SHUT_WR). Это не обязательно означает, что сокет мертв. Последующие вызовы recv () вернут все непрочитанные данные на сокете, и в конечном итоге будет возвращено «0» для обозначения EOF. Возможно даже отправить данные обратно, если удаленный узел только наполовину закроет свой сокет.

Единственное заметное исключение - если удаленный узел использует опцию SO_LINGER, включенную в его сокете с задержанным значением "0". Результат закрытия такого сокета может привести к отправке TCP RST вместо FIN. Из того, что я прочитал, событие сброса соединения будет генерировать либо EPOLLHUP, либо EPOLLERR. (У меня не было времени для подтверждения, но это имеет смысл).

Существует некоторая документация, позволяющая предположить, что есть более старые реализации Linux, которые не поддерживают EPOLLRDHUP, так как вместо этого создается EPOLLHUP.

И для чего это стоит, в моем конкретном случае я обнаружил, что не слишком интересно иметь код, который является особым случаем событий EPOLLHUP или EPOLLRDHUP. Вместо этого просто обработайте эти события так же, как EPOLLIN / EPOLLOUT, и вызовите recv () (или send () в зависимости от ситуации). Но обратите пристальное внимание на коды возврата, возвращаемые из recv () и send ().

...