LINUX.ORG.RU

как правильно узнать, что клиент отвалился?

 , ,


0

1
sockfd = accept(...);
// ...
while(1) {
    fd_set rd;
    // ...
    FD_SET(sockfd, &rd);
    // ...
    select(nfds, rd, 0, 0, 0);
    if(FD_ISSET(sockfd, &fd) {
        ssize_t rd_sz;
        rd_sz = recv(sockfd, buf, buf_sz, O_NONBLOCK)
        // ...
    }
}

если клиент закрывает соединение, то цикл начинает крутится без остановки — select сразу возвращает, что можно читать. recv возвращает 0

как идеологически правильно узнать, что клиент отвалился?

знаю о POLLRDHUP - но это только в linux'е и только с 2.6.17. ещё рассказали о хаке: можно написать в MSG_OOB если ошибка, то соединение крякнулось, но костыльно и в теории MSG_OOB может использоваться для чего-то полезного.



Последнее исправление: Fat-Zer (всего исправлений: 2)

Ответ на: комментарий от Vinick

Вроде бы recv, возвращающий 0, и есть сигнал о закрытии соединения.

а select'у мы точно можем доверять, что он просто так не вернётся?

Fat-Zer
() автор топика

у select 4 параметр - exceptfds. Не будет ли при закрытии сокета туда он попадать?

anonymous
()
Ответ на: комментарий от anonymous

у select 4 параметр - exceptfds. Не будет ли при закрытии сокета туда он попадать?

проверял, нет... man говорит он прежде всего для прихода сообщения в MSG_OOB.

Fat-Zer
() автор топика

0(при errno != EWOULDBLOCK) от ресв и есть сигнал о закрытии соединения.
Посля этого список файл дескрипторов для селекта надо обновить.

Jetty ★★★★★
()
Ответ на: комментарий от Fat-Zer

Как я понял из мана, если после возвращения из select() сокет отмечен, что имеет данные для чтения, но размер этих данных равен 0 - то сокет закрыт. Если данных нет для чтения, то он не должен быть отмечен.

anonymous
()
Ответ на: комментарий от Fat-Zer

Так мы ж не просто на select полагаемся. После того что он вернулся, вызываем read/recv на отмеченные им сокеты. Если read/recv возвращает 0 - всё, на той стороне больше никого нет. Ведь read должен возвращать или кол-во прочитанных байт, или -1 в случае ошибки, а 0 - EOF.

gag ★★★★★
()
Ответ на: комментарий от gag

понял своё заблуждение: думал, что с MSG_DONTWAIT будет возвращать 0, если нечего читать... значит recv() возвращающий 0 и будет ответом... [РЕШЕНО]

кстати ещё одна ошибка: нужно использовать MSG_DONTWAIT в recv() и O_NONBLOCK в fcntl. эти константы не равны...

Fat-Zer
() автор топика

Может быть, если recv возвращает 0, то всё?

KivApple ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.