2010-05-20 6 views
80

Comment puis-je essayer de lire les données à partir du socket avec le délai d'attente? Je sais, sélectionnez, pselect, poll, a un champ de délai d'attente, mais l'utilisation d'eux désactive "tcp fast-path" dans la pile tcp reno.Linux: y a-t-il une lecture ou une recv de la socket avec timeout?

La seule idée que j'ai est d'utiliser recv (fd, ..., MSG_DONTWAIT) dans une boucle

+0

Il y a aussi une possibilité d'utiliser des fils :) mais les signaux de fil toujours nécessaire – osgx

Répondre

147

Vous pouvez utiliser la fonction setsockopt pour définir un délai d'attente lors de la réception des opérations:

SO_RCVTIMEO

Définit la valeur de délai d'attente qui spécifie le montant maximum de temps une fonction entrée attend jusqu'à ce qu'il complète. Il accepte une structure timeval avec le nombre de secondes et microsecondes spécifiant la limite sur combien de temps à attendre une opération d'entrée à terminée. Si une opération de réception a bloqué pour tout ce temps sans recevoir des données supplémentaires, il doit retour avec un décompte partiel ou errno réglé sur [EAGAIN] ou [EWOULDBLOCK] si aucune donnée est reçue. La valeur par défaut pour cette option est zéro, ce qui indique qu'une opération de réception ne doit pas expirer. Cette option prend une structure timeval. Notez que toutes les implémentations ne permettent pas de définir cette option.

// 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); 

Reportedly sous Windows, il devrait être fait avant d'appeler bind. J'ai vérifié par l'expérience que cela peut être fait avant ou après bind sous Linux et OS X.

+2

Cela fonctionnera-t-il pour linux 2.6 tcp? udp? – osgx

+5

Oui, il le fera. Merci beaucoup – osgx

+0

Cela ne fonctionne pas sur Windows .... – Mendes

0

Installer un gestionnaire pour SIGALRM, puis utilisez alarm() ou ualarm() avant un blocage recv() régulier. Si l'alarme se déclenche, le recv() renvoie une erreur avec errno définie sur EINTR.

+8

des alarmes (et signaux) sont la mauvaise façon à ce tâche. Si je veux utiliser le raccourci tcp, j'ai besoin d'une latence minimale. Les signaux sont lents. – osgx

+1

@osgx Le signal ne se produit que s'il y a un timeout. –

13

Voici un code simple pour ajouter le temps à votre fonction recv utilisant sondage en 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; 
} 
-1

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)); 

NOTE: Vous avez mis ce paramètre avant bind() appel de fonction pour l'exécution correcte

+2

Cette question a déjà été répondue il y a des années. Quelle nouvelle valeur apporte votre solution? –

+0

Vous avez mis ce paramètre avant l'appel de la fonction bind() pour une exécution correcte cette partie n'est pas mentionnée dans – vivek

Questions connexes