Linux: есть ли чтение или recv из сокета с таймаутом?

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

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

5 ответов


можно использовать setsockopt функция для установки тайм-аута при операциях приема:

SO_RCVTIMEO

задает значение тайм-аута, который определяет максимальное количество времени ввода функция ожидает завершения. Он принимает структуру timeval с количество секунд и микросекунд указание предельного срока ждать операции ввода полный. Если получите операции заблокирован для столько времени без получая дополнительные данные, она возврат с частичным подсчетом или errno значение [или] или [EWOULDBLOCK] если нет полученные данные. По умолчанию для этого параметр равен нулю, что означает, что a время работы receive не истекает. Этот параметр принимает структуру timeval. Обратите внимание, что не все реализации разрешить установку этого параметра.

// 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.


вот простой код для добавления тайм-аута к вашей функции recv с помощью опроса в 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;
}

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


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

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

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() вызов функции для правильного выполнения