Сокет с recv-timeout: что не так с этим кодом? - PullRequest
10 голосов
/ 26 декабря 2008

Я пытаюсь реализовать сокет с тайм-аутом recv, равным 1 секунде:

int sockfd;
struct sockaddr_in self;
struct sockaddr_in client_addr;
int addrlen=sizeof(client_addr);
ssize_t nBytes;

sockfd = socket(AF_INET, SOCK_STREAM, 0);

self.sin_family = AF_INET;
self.sin_port = htons(PORT);
self.sin_addr.s_addr = INADDR_ANY;

int on = 1;
setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on);

// 1 Sec Timeout
tv.tv_sec  = 1;  
tv.tv_usec = 0;
setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv);

bind(sockfd, (struct sockaddr*)&self, sizeof(self));

listen(sockfd, 20);

clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen);

nBytes = recv(clientfd, buffer, MAXBUF-1, 0);

Без 'setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, & tv, sizeof (tv);' вызовы для принятия и получения работают, но блоки recv.

При использовании 'setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO и & tv, sizeof (tv);' вызов принять вызывает ошибку 'Ресурс временно недоступен'.

Может кто-нибудь сказать мне, что не так с этим подходом?

Ответы [ 6 ]

6 голосов
/ 26 декабря 2008

В каком сокете вы хотите установить тайм-аут на одну секунду? Тот, который принимает соединения, или тот, который установлен accept ()?

Я бы предположил последнее - так что попробуйте установить время ожидания на clientfd ПОСЛЕ подтверждения возврата Вы также можете добраться туда, где вам нужно использовать select, но вам не нужно.

5 голосов
/ 06 июня 2014

Это немного не по теме, но я действительно хочу поделиться этим решением, чтобы установить время ожидания recv как в Windows, так и в Unix. Может быть, это я, но мне потребовалось много времени, чтобы понять, почему моя программа не работает и как правильно установить время ожидания. Надеюсь, что вы найдете ее полезной. Устанавливает тайм-аут на 10 секунд.

Для Windows:

DWORD sock_timeout = 10*1000;

Для Unix:

const struct timeval sock_timeout={.tv_sec=10, .tv_usec=0};

Для обоих:

setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&sock_timeout, sizeof(sock_timeout));
4 голосов
/ 26 декабря 2008

Вот фрагмент кода, использующий select:

FD_ZERO(&masterfds);
FD_SET(sockfd,&masterfds);
memcpy(&readfds,&masterfds,sizeof(fd_set));
timeout.tv_sec = 2;
timeout.tv_usec = 0;
if (select(sockfd+1, &readfds, NULL, NULL, &timeout) < 0)
{
    printf("select error");
    exit(1);
}

if (FD_ISSET(sockfd, &readfds))
{
    //printf("Read from socket\n");
    // read from the socket
    res = recvfrom(sockfd, (char *)hdrbuf, sizeof(hdrbuf), MSG_PEEK, recvaddr, address_len);
}
else
{
    // the socket timedout
    //printf("Socket timeout started=%d\n",packets_started);
1 голос
/ 06 января 2012

Вам понадобится еще одна закрывающая скобка в каждой из этих двух строк.

- setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on);
+ setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv);
+ setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
1 голос
/ 18 мая 2011

Ничего плохого ... Код ошибки EAGAIN (ресурс временно недоступен) - это именно то, что вы должны получить после истечения времени ожидания!

0 голосов
/ 26 декабря 2008

Попробуйте использовать select () перед вызовом recv () или accept ().

select () принимает массив файловых дескрипторов (включая сокеты) и возвращает, когда хотя бы один из них готов к приему. Он также может вернуться по таймауту.

В linux вы также можете попробовать poll () (не уверен, что Winsock предоставляет это).

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