Utilisation appropriée de getsockopt et setsockopt pour SO_RCVTIMEO et SO_SNDTIMEO

Par diverses raisons, j'aimerais mettre en œuvre délai d'attente de la lecture et de l'écriture à la prise d'un serveur, mais ne parviennent pas à obtenir l'exécution et, par conséquent, de bien vouloir demander pour un aperçu de la où le problème peut résider.

Afin de définir le délai d'attente sur la lecture et l'écriture à la prise, je suis en train d'utiliser des fonctions setsocketopt() et getsocketopt(). Toutefois, je dois être en train de faire quelque chose de mal comme valeur de retour indique qu'un problème est survenu et perror sorties "argument non Valide". Assez étrangement, l'erreur ne se produit pas toujours à la première utilisation de la setsocketopt() et getsocketopt(), ce qui m'intrigue, c'bits.

La suite du serveur et du client des codes reproduit mes problèmes (compilé avec gcc)

code serveur:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h>  
int main() {
struct sockaddr_in saddr,caddr; 
socklen_t clen;
int sock, csock, reuse = 1, ret=0;
socklen_t ntrcv, ntsnd;
struct timeval tout, tsnd, trcv;
//create a new stream socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) perror("failed to create socket");
else {          
//enable the socket to reuse the address
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) perror("failed allowing server socket to reuse address");
else {
//set up the server address
memset((char *) &saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
saddr.sin_port = htons(45454);
//bind socket to address
if (bind(sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) perror("failed to bind");
else {
//listen to the socket for connections 
if (listen(sock,5) < 0) perror("failed to listen");
else {
clen = sizeof(caddr);
if ((csock = accept(sock, (struct sockaddr *) &caddr, &clen)) < 0) perror("failed to accept");
else {
tout.tv_sec=0;
tout.tv_usec=10000;
//check value of errno prior to setting timeout
perror("errno prior to timeout");
if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &trcv, &ntrcv) < 0) perror("2");
else if (getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tsnd, &ntsnd) < 0) perror("3");
else if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tout, sizeof(tout)) < 0) perror("4");
else if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tout, sizeof(tout)) < 0) perror("5");
else {
printf ("all ok so far in server\n");
sleep(1);
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &trcv, ntrcv) < 0) perror("6");
else if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tsnd, ntsnd) < 0) perror("7");
}
if (close(csock) < 0) perror("failed to close csock");
}
}
}
}
}
if (close(sock) < 0) perror("failed to close sock");
return ret;
}

code client:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
struct sockaddr_in addr;     
struct hostent *server; 
int sock = 0;
//resolve server name
if (!(server = gethostbyname("127.0.0.1"))) perror("failed to resolve host");
else {
//prepare the server address
memset((char *) &addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&addr.sin_addr.s_addr, server->h_length);
addr.sin_port = htons(45454);
//create a socket and connect to the server
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) perror("failed to create client socket");
else {
if (connect(sock,(struct sockaddr *) &addr,sizeof(addr)) < 0) perror("failed to connect to server");
else {
printf("Connection is established will sleep now\n");
sleep(3);
printf("done sleeping\n");
close(sock);
printf("socket is closed\n");
}
}
}
return 0;
}

Dans le présent exemple, le deuxième appel à getsockopts() dans le serveur tombe en panne résultant dans perror("3") à être appelé. Si j'toutefois commenter cette ligne de sortie ainsi que le dernier appel à setsockopts() le premier appel à getsockopts() échoue (ce qui semblait auparavant de travail).

Des idées à l'endroit où je vais mal apprécié

Pouvez-vous nous parler de votre approche pour la définition de ces options de prise? Vous définissez d'abord la valeur de SO_RCVTIMEO à tout (étant la valeur que vous souhaitez être appliqué), mais après une seconde de sommeil, vous retournez à la trcv (la valeur d'origine). Je ne suis pas à voir la finalité de cette. Pouvez-vous développer?
Salut Gleerman, désolé d'être imprécise, la ligne sleep(1) a été prévu lors de mon test et devrait être remplacé (ainsi que le précédent appel à printf() ) avec les tâches que le serveur est censé effectuer. Une fois fait, je réinitialiser SO_RCVTIMEO à sa valeur d'origine.

OriginalL'auteur cpaitor | 2015-01-30