Come posso provare a leggere i dati dal socket con timeout? Lo so, select, pselect, poll, ha un campo timeout, ma il loro utilizzo disabilita "tcp fast-path" nello stack tcp reno.
L'unica idea che ho è usare recv (fd, ..., MSG_DONTWAIT) in un ciclo
Come posso provare a leggere i dati dal socket con timeout? Lo so, select, pselect, poll, ha un campo timeout, ma il loro utilizzo disabilita "tcp fast-path" nello stack tcp reno.
L'unica idea che ho è usare recv (fd, ..., MSG_DONTWAIT) in un ciclo
Risposte:
È possibile utilizzare la funzione setsockopt per impostare un timeout sulle operazioni di ricezione:
SO_RCVTIMEO
Imposta il valore di timeout che specifica la quantità massima di tempo che una funzione di input attende fino al suo completamento. Accetta una struttura temporale con il numero di secondi e microsecondi che specifica il limite di tempo di attesa per il completamento di un'operazione di input. Se un'operazione di ricezione si è bloccata per così tanto tempo senza ricevere dati aggiuntivi, tornerà con un conteggio parziale o errno impostato su [EAGAIN] o [EWOULDBLOCK] se non vengono ricevuti dati. Il valore predefinito per questa opzione è zero, che indica che un'operazione di ricezione non deve scadere. Questa opzione ha una struttura temporale. Notare che non tutte le implementazioni consentono di impostare questa opzione.
// 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);
Secondo quanto riferito su Windows, questo dovrebbe essere fatto prima di chiamare bind
. Ho verificato per esperimento che può essere fatto prima o dopo bind
su Linux e OS X.
struct timeval tv;
, significa che anche select () non funzionerà? Ho provato a portare il mio codice select () su Windows e si è appena verificato un timeout immediatamente, sembra che stia ignorando il valore che sto impostando al momento.
Ecco un semplice codice per aggiungere un timeout alla tua recv
funzione utilizzando poll
in 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
attenderà di ricevere almeno un byte o timeout, mentre chiamando la recv
funzione attenderà i sizeof(buf)
byte, provocando il blocco di nuovo se questo conteggio non è ancora arrivato, ma questa volta senza avere timeout.
// funziona anche dopo l'operazione di bind per WINDOWS
DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
Installa un gestore per SIGALRM
, quindi usa alarm()
o ualarm()
prima di un blocco regolare recv()
. Se l'allarme si spegne, recv()
restituirà un errore con errno
impostato su 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));
FINESTRE
DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
NOTA : questa impostazione è stata inserita prima della bind()
chiamata di funzione per una corretta esecuzione