Это архив сайта coldflame.by.ru, он не обновлялся с 2007 года. Мой современный сайт тут: http://leonid.shevtsov.me.
Домой! Обо мне Специально для РИ-06-1 Разнообразное... барахло, короче :) Программы и прочее Статьи и переводы Блог SmartDaemon
Предыдущая ОглавлениеСледующая

poll()

Опросить несколько сокетов одновременно

Прототип

#include <sys/poll.h>

int poll(struct pollfd *ufds, unsigned int nfds, int timeout);

Описание

Эта функция очень похожа на select() в том, что обе они проверяют набор дескрипторов на события, типа входящих данных, готовых к recv(), сокетов, готовых к send(), ошибок и т.п.

Ты передаешь массив из nfds структур pollfd в ufds, а также таймаут в миллисекундах (в 1 секунде 1000 миллисекунд.) Если не произойдет никаких событий до истечения таймаута, poll() завершится. timeout может быть отрицательным - тогда poll() будешь ждать вечно.

Каждый элемент массива структур pollfd описывает один дескриптор сокета, и содержит такие поля:

struct pollfd {
    int fd;         // номер дескриптора
    short events;   // флаги событий, за которыми нужно следить
    short revents;  // после вызова poll(), флаги произошедших событий
};

Перед вызовом poll(), запиши в fd дескриптор сокета (если fd будет отрицательным, этот элемент массива проигнорируется и поле revents будет равно нулю) и собери поле events логическим сложением следующи макросов:

POLLIN

Сообщи, когда в сокете есть входящие данные

POLLOUT

Сообщи, когда в сокет можно слать данные (без блокирования)

POLLPRI

Сообщи, когда в сокете появятся внепотоковые данные (out-of-band).

После вызова poll(), поле revents будет содержать логическую сумму произошедших событий, плюс следующих флагов:

POLLERR

Произошла ошибка.

POLLHUP

Удаленная сторона закрыла соединение.

POLLNVAL

Сокет fd не готов - может, он не инициализирован?

Возвращаемое значение

Возвращает количество элементов в массиве ufds, в которых произошли события; если функция завершилась по таймауту, она вернет ноль. Если произошла ошибка, она вернет -1 и сохранит номер ошибки вerrno

Пример

int s1, s2;
int rv;
char buf1[256], buf2[256];
struct pollfd ufds[2];

s1 = socket(PF_INET, SOCK_STREAM, 0);
s2 = socket(PF_INET, SOCK_STREAM, 0);

// здесь мы соединяем оба сокета с серверами
//connect(s1, ...)...
//connect(s2, ...)...

// собираем массив дескрипторов
//
// в этом примере мы хотим узнать, есть ли обычные или
// внепотоковые данные, готовые к recv()...

ufds[0].fd = s1;
ufds[0].events = POLLIN | POLLPRI; // обычные и внепотоковые

ufds[1] = s2;
ufds[1].events = POLLIN; // только обычные

// ждем событий, таймаут 3.5 секунды
rv = poll(ufds, 2, 3500);

if (rv == -1) {
    perror("poll"); // произошла ошибка в poll()
} else if (rv == 0) {
    printf("Таймаут!  За 3.5 секунды данные не поступали.\n");
} else {
    // проверяем события на s1:
    if (ufds[0].revents & POLLIN) {
        recv(s1, buf1, sizeof(buf1), 0); // получаем обычные данные
    }
    if (ufds[0].revents & POLLPRI) {
        recv(s1, buf1, sizeof(buf1), MSG_OOB); // внепотоковые данные
    }

    // проверяем события на s2:
    if (ufds[1].revents & POLLIN) {
        recv(s1, buf2, sizeof(buf2), 0);
    }
}

См. также

select()


Предыдущая ОглавлениеСледующая