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