Приведенный ниже фрагмент сначала проверяет, помечен ли сокет как читаемый (каковым он является при закрытии), а затем проверяет, есть ли что-нибудь для чтения.
#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;
}