web-dev-qa-db-fra.com

Linux: existe-t-il une lecture ou une réception depuis un socket avec timeout?

Comment puis-je essayer de lire des données depuis socket avec timeout?.

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

86
osgx

Vous pouvez utiliser la fonction setsockopt pour définir un délai d'expiration pour les opérations de réception:

SO_RCVTIMEO

Définit la valeur de délai qui spécifie la durée maximale d'une entrée la fonction attend jusqu'à ce qu'elle se termine. Il accepte une structure temporelle avec le nombre de secondes et microsecondes spécifiant la limite de temps pour attendre une opération d'entrée à Achevée. Si une opération de réception a bloqué pour autant de temps sans recevoir des données supplémentaires, il doit revenir avec un compte partiel ou errno régler sur [EAGAIN] ou [EWOULDBLOCK] si non. les données sont reçues. La valeur par défaut pour cela L'option est zéro, ce qui indique qu'un L'opération de réception ne doit pas expirer . Cette option prend une structure temporelle . Notez que pas toutes les implémentations permettre à cette option d'être définie.

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

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

162
Robert S. Barnes

Voici un code simple pour ajouter du temps à votre fonction recv en utilisant 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;
}
17
Abdessamad Doughri

Installez un gestionnaire pour SIGALRM, puis utilisez alarm() ou ualarm() avant une recv() bloquante normale. Si l'alarme se déclenche, la recv() renvoie une erreur avec errno défini sur EINTR.

0
caf

// fonctionne aussi après l'opération de liaison pour WINDOWS

DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
0
cahit beyaz