Linux: есть ли чтение или recv из сокета с таймаутом?
Как я могу попытаться прочитать данные из сокета с таймаутом? Я знаю, select, pselect, poll, имеет поле timeout, но использование их отключает "tcp fast-path" в стеке tcp reno.
единственная идея у меня заключается в использовании приема(ФД ..., MSG_DONTWAIT) в цикле
5 ответов:
можно использовать 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.
вот простой код, чтобы добавить тайм-аут к вашей функции 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()
вызов функции для правильного выполнения