Linux: есть чтение или запись из сокета с таймаутом? - PullRequest
89 голосов
/ 20 мая 2010

Как я могу попытаться прочитать данные из сокета с тайм-аутом? Я знаю, что у select, pselect, poll есть поле тайм-аута, но использование их отключает «быстрый путь tcp» в стеке tcp reno.

Единственная идея, которую я имею, это использовать recv (fd, ..., MSG_DONTWAIT) в цикле

Ответы [ 5 ]

168 голосов
/ 30 мая 2010

Вы можете использовать функцию setsockopt , чтобы установить тайм-аут для операций приема:

SO_RCVTIMEO

Устанавливает значение времени ожидания, которое указывает максимальное количество времени на вход Функция ждет, пока не завершится. Это принимает временную структуру с количество секунд и микросекунд указав предел как долго ждать операции ввода для полный. Если операция получения имеет заблокировано на это много времени без Получив дополнительные данные, он должен вернуть с частичным счетом или ошибкой установите на [EAGAIN] или [EWOULDBLOCK], если нет данные получены. По умолчанию для этого опция равна нулю, что означает, что Операция приема не должна прерываться. Эта опция требует временной структуры. Обратите внимание, что не все реализации разрешить установку этой опции.

// LINUX
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);

// WINDOWS
DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);

// MAC OS X (identical to Linux)
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);

По сообщениям в Windows, это следует сделать перед вызовом bind. Я экспериментально подтвердил, что это можно сделать до или после bind в Linux и OS X.

18 голосов
/ 29 сентября 2015

Вот простой код для добавления времени ожидания к вашей функции recv с помощью poll в C:

struct pollfd fd;
int ret;

fd.fd = mySocket; // your socket handler 
fd.events = POLLIN;
ret = poll(&fd, 1, 1000); // 1 second for timeout
switch (ret) {
    case -1:
        // Error
        break;
    case 0:
        // Timeout 
        break;
    default:
        recv(mySocket,buf,sizeof(buf), 0); // get your data
        break;
}
0 голосов
/ 04 апреля 2018

// работает также после операции связывания для WINDOWS

DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
0 голосов
/ 30 августа 2017

LINUX

struct timeval tv;
tv.tv_sec = 30;        // 30 Secs Timeout
tv.tv_usec = 0;        // Not init'ing this can cause strange errors
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));

Windows

DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));

ПРИМЕЧАНИЕ : Вы установили эту настройку перед bind() вызовом функции для правильного запуска

0 голосов
/ 21 мая 2010

Установите обработчик для SIGALRM, затем используйте alarm() или ualarm() перед обычной блокировкой recv(). Если сигнал тревоги сработает, recv() вернет ошибку с errno, установленным на EINTR.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...