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é
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
Vous devez vous connecter pour publier un commentaire.
Vous n'êtes pas en cours d'initialisation
ntsnd
etntrcv
à la taille de la mémoire tampon disponible àgetsockopt
. Par conséquent, si la valeur aléatoire il y a une plus grande ou égale à la taille nécessaire, l'appel va réussir. Sinon, il échouera avecEINVAL
. À partir de la page de man:Pour résoudre ce initialiser tous les deux à la
sizeof(struct timeval)
.Pas de problème, la meilleure façon de dire merci est d'accepter la réponse 🙂
Eh bien, il semble être un certain délai avant de pouvoir accepter, mes premières tentatives simplement affiché une boîte rouge avec le texte "il y a x minutes untilm vous pouvez accepter la réponse" (ou similaire)
Veuillez utiliser le code de formatage de code, et devis de mise en forme pour les citations.
J'ai posté à ce sujet sur meta la dernière fois que vous avez ramassé sur cette. Je n'ai pas utiliser la mise en forme du code. J'ai utilisé AVANT les balises. Tel est le consensus sur meta quant à ce qui devrait être fait. Voir meta.stackoverflow.com/questions/284689/...
OriginalL'auteur abligh
Vous devez définir la
ntsnd
etntrcv
variables àsizeof ntsnd
etsizeof ntrcv
respectivement, ousizeof struct timeval
.OriginalL'auteur user207421