С++, как использовать select, чтобы увидеть, закрыт ли сокет
Может ли кто-нибудь предоставить мне пример использования select(), чтобы узнать, закрыл ли клиент соединение в сокете?
FYI. Я использую linux.
Спасибо!
Ответ 1
В приведенном ниже фрагменте сначала проверяется, является ли сокет отмеченным читаемым (который он закрыт), а затем, если есть что-нибудь, что нужно прочитать.
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
bool isclosed(int sock) {
fd_set rfd;
FD_ZERO(&rfd);
FD_SET(sock, &rfd);
timeval tv = { 0 };
select(sock+1, &rfd, 0, 0, &tv);
if (!FD_ISSET(sock, &rfd))
return false;
int n = 0;
ioctl(sock, FIONREAD, &n);
return n == 0;
}
Ответ 2
Вам не нужно делать select(), а затем ioctl(). Вместо этого вы можете сделать неблокирующий просмотр в сокете, чтобы увидеть, возвращает ли он 0.
bool isclosed (int sock) {
char x;
interrupted:
ssize_t r = ::recv(sock, &x, 1, MSG_DONTWAIT|MSG_PEEK);
if (r < 0) {
switch (errno) {
case EINTR: goto interrupted;
case EAGAIN: break; /* empty rx queue */
case ETIMEDOUT: break; /* recv timeout */
case ENOTCONN: break; /* not connected yet */
default: throw(errno);
}
}
return r == 0;
}
Ответ 3
Если вы получаете уведомление о чтении, а чтение возвращает 0 байтов, клиент вышел из него чисто. Если нет, вы получите уведомление об исключении.
Ответ 4
Если клиент закрыл чисто, вы должны получить уведомление о том, что READ не будет блокироваться, а EXCEPTION (третий набор) помечен.
Если клиент закрыл аборт, вы не знаете. Это зависит от проблемы двух генералов.