Linux: há uma leitura ou recv do soquete com tempo limite?
105
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
Também existe a opção de usar threads :) mas os sinais de thread ainda são necessários
osgx
Respostas:
189
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.
// LINUXstruct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec =0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,(constchar*)&tv,sizeof tv);// WINDOWS
DWORD timeout = timeout_in_seconds *1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO,(constchar*)&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,(constchar*)&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 bindno Linux e no OS X.
Essa resposta salvou minha bunda. Eu estava preso na implementação daquela porcaria complicada de "selecionar", sem sucesso. Isso funcionou imediatamente, muito mais simples.
MiloDC
É por isso que o tempo limite no windows não está funcionando porque estou usando o código para linux. Obrigado. Se o Windows não estiver usando 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.
kuchi
1
Defino o valor do tempo limite para 5 segundos. Por que sempre leva 5 segundos para cada ciclo de leitura, independentemente de haver dados de entrada ou não?
Han
isso também funciona no Windows, mesmo após a operação de ligação. experimentado no windows 10
Aqui está um código simples para adicionar um tempo limite à sua recvfunção usando pollem C:
struct pollfd fd;int ret;
fd.fd = mySocket;// your socket handler
fd.events = POLLIN;
ret = poll(&fd,1,1000);// 1 second for timeoutswitch(ret){case-1:// Errorbreak;case0:// Timeout break;default:
recv(mySocket,buf,sizeof(buf),0);// get your databreak;}
isso não funcionaria exatamente como esperado. pollirá esperar pelo recebimento de pelo menos um byte ou timeout, ao passo que ao chamar a recvfunçã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.
LoPiTaL
0
// funciona também após a operação de ligação para WINDOWS
Instale um manipulador para SIGALRMe use alarm()ou ualarm()antes de um bloqueio regular recv(). Se o alarme disparar, o recv()retornará um erro com errnodefinido para EINTR.
Respostas:
Você pode usar a função setsockopt para definir um tempo limite nas operações de recebimento:
Supostamente, no Windows, isso deve ser feito antes de ligar
bind
. Eu verifiquei por experiência que isso pode ser feito antes ou depoisbind
no Linux e no OS X.fonte
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 usandopoll
em C:fonte
poll
irá esperar pelo recebimento de pelo menos um byte ou timeout, ao passo que ao chamar arecv
função irá esperar ossizeof(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
fonte
Instale um manipulador para
SIGALRM
e usealarm()
ouualarm()
antes de um bloqueio regularrecv()
. Se o alarme disparar, orecv()
retornará um erro comerrno
definido paraEINTR
.fonte
LINUX
JANELAS
NOTA : Você colocou esta configuração antes da
bind()
chamada de função para uma execução adequadafonte