c++ how to use select to see if a socket has close

2019-01-08 21:22发布

问题:

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!

回答1:

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;
}


回答2:

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;
}


回答3:

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.



回答4:

If the client has closed cleanly you should get notification that READ will not block and EXCEPTION (third set) is flagged.

If the client has closed abortively you do not know. This is subject to the two generals problem.