Linux: проверка, не сломан ли сокет / канал, без выполнения read () / write () - PullRequest
7 голосов
/ 09 февраля 2012

У меня есть простой кусок кода, который периодически записывает данные в fd, который передается ему.Скорее всего, fd будет трубой или сокетом, но потенциально может быть чем угодно.Я могу определить, когда сокет / канал закрывается / прерывается всякий раз, когда я пишу () в него, так как я получаю ошибку EPIPE (я игнорирую SIGPIPE).Но я не пишу в него все время, и поэтому не могу обнаружить закрытый сокет в течение длительного времени.Я должен реагировать на закрытие как можно скорее.Есть ли способ проверки FD без необходимости писать ()?Я мог бы делать это периодически, если я ничего не пишу.

Ответы [ 3 ]

8 голосов
/ 09 февраля 2012
struct pollfd pfd = {.fd = yourfd, .events = POLLERR};
if (poll(&pfd, 1, whatever) < 0) abort();
if (pfd.revents & POLLERR) printf("pipe is broken\n");

Это работает для меня.Обратите внимание, что сокеты не являются в точности конвейерами и, следовательно, демонстрируют различное поведение (-> использовать POLLRDHUP).

2 голосов
/ 09 февраля 2012

Попробуйте с select и его параметром errorfds:

int **select**(int nfds, fd_set *restrict readfds,
      fd_set *restrict writefds, **fd_set *restrict errorfds**,
      struct timeval *restrict timeout);
1 голос
/ 28 июня 2012

Хорошие ответы, они мне нравятся ... Мне также нужно выбраться из избранного и в опрос (е).

Вот несколько более традиционных методов, если они вам нужны:

/* check whether a file-descriptor is valid */
int fd_valid(int fd)
{   
    if (fcntl(fd, F_GETFL) == -1 && errno == EBADF) return FALSE;
    return TRUE;
}       

Этот пытается дублировать сокет / fd. Это намного проще, чем во взглядах, я оставил много отладки.

/* check a file descriptor */
int fd_check(int i) {
    int fd_dup = dup(i);
    if (fd_dup == -1) {
        strcpy(errst, strerror(errno));
        // EBADF  oldfd isn’t an open file descriptor, or newfd is out of the allowed range for file descriptors.
        // EBUSY  (Linux only) This may be returned by dup2() during a race condition with open(2) and dup().
        // EINTR  The dup2() call was interrupted by a signal; see signal(7).
        // EMFILE The process already has the maximum number of file descriptors open and tried to open a new one.

        if (errno == EBADF) {
            return FALSE;
        }   

        return TRUE;
    }   
    close(fd_dup);
    return TRUE;
}   
...