c++ how to use select to see if a socket has closed
Can someone provide me an example of how开发者_开发百科 to use select() to see if a client has closed the connection on a socket?
FYI. I'm using linux.
Thanks!
The below snippet first checks if the socket is marked readable (which it is when closed) and then if there's actually anything to be read.
#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;
}
You don't need to do a select()
followed by ioctl()
. You can instead do a non-blocking peek on the socket to see if it returns 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;
}
If you get a read notification and the read returns 0 bytes the client has exited cleanly. If not you will get an exception notification.
Here is an example to checks if the socket is closed by peer WITHOUT reading form it in case of non-empty recv buffer.
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* FOR: POLLRDHUP define */
#endif
#include <poll.h>
bool connection_peer_closed(int fd)
{
struct pollfd pfd;
int ret;
if (fd < 0) {
return true;
}
pfd.fd = fd;
pfd.events = POLLRDHUP;
pfd.revents = 0;
ret = poll(&pfd, 1, 0);
if (ret > 0 && (pfd.revents & (POLLHUP | POLLERR | POLLRDHUP))) {
return true;
} else {
return false;
}
}
精彩评论