Como posso tentar ler dados do soquete com tempo limite? Eu sei, select, pselect, poll, tem um campo de tempo limite, mas o uso deles desativa "tcp fast-path" na pilha tcp reno.
A única ideia que tenho é usar recv (fd, ..., MSG_DONTWAIT) em um loop
Como posso tentar ler dados do soquete com tempo limite? Eu sei, select, pselect, poll, tem um campo de tempo limite, mas o uso deles desativa "tcp fast-path" na pilha tcp reno.
A única ideia que tenho é usar recv (fd, ..., MSG_DONTWAIT) em um loop
Respostas:
Você pode usar a função setsockopt para definir um tempo limite nas operações de recebimento:
SO_RCVTIMEO
Define o valor de tempo limite que especifica a quantidade máxima de tempo que uma função de entrada espera até ser concluída. Ele aceita uma estrutura de valor de tempo com o número de segundos e microssegundos especificando o limite de quanto tempo esperar pela conclusão de uma operação de entrada. Se uma operação de recebimento foi bloqueada por tanto tempo sem receber dados adicionais, ela deve retornar com uma contagem parcial ou errno definido como [EAGAIN] ou [EWOULDBLOCK] se nenhum dado for recebido. O padrão para esta opção é zero, o que indica que uma operação de recebimento não deve expirar. Esta opção tem uma estrutura temporal. Observe que nem todas as implementações permitem que essa opção seja definida.
// 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);
Supostamente, no Windows, isso deve ser feito antes de ligar bind
. Eu verifiquei por experiência que isso pode ser feito antes ou depois bind
no Linux e no OS X.
struct timeval tv;
, isso significa que select () também não funcionará? Tentei portar meu código select () para o windows e ele atinge o tempo limite imediatamente, parece que está ignorando o valor que estou definindo em timeval.
Aqui está um código simples para adicionar um tempo limite à sua recv
função usando poll
em 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;
}
poll
irá esperar pelo recebimento de pelo menos um byte ou timeout, ao passo que ao chamar a recv
função irá esperar os sizeof(buf)
bytes, fazendo com que bloqueie novamente se esta contagem ainda não tiver chegado, mas desta vez sem ter um timeout.
// funciona também após a operação de ligação para WINDOWS
DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
Instale um manipulador para SIGALRM
e use alarm()
ou ualarm()
antes de um bloqueio regular recv()
. Se o alarme disparar, o recv()
retornará um erro com errno
definido para EINTR
.
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));
JANELAS
DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
NOTA : Você colocou esta configuração antes da bind()
chamada de função para uma execução adequada