Bonjour à tous,
Voilà je dispose d'un client et d'un serveur (appelés émetteur et receveur).
Grosso modo :
l'émetteur envoie un fichier texte au receveur. Après chaque paquet envoyé, il attend la réception d'un ack.
le receveur attend des paquets. a chaque paquet reçu il envoie un ack
Mon problème est que je reste bloqué sur l'émetteur après l'appel à la fonction reception()
CODE DE l'EMETTEUR
CODE DU RECEVEUR :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 /******************************************************* Nom ......... : emetteur.c Role ........ : Client UDP Compilation : make all ********************************************************/ #include "librairies.h" #include "socket.h" #define DEBUG_MODE int main (int argc, char *argv[]) { /*Variables*/ int emetteur;/*Descripteur de la socket*/ char bufenvoi[MAX_BUF]; int ret_envoi; /**/ char bufreception[MAX_BUF]; int ret_reception; /**/ char ligne[MAX_BUF];/*Ligne (du fichier) en cours d'envoi au récepteur*/ int error; struct sockaddr_in receveur;/**/ struct in_addr *ip_receveur;/**/ struct hostent *h; /*Utilisé pour la resolution des noms de domaine (DNS)*/ FILE *fichier=fopen("fichier_demo.txt", "r");/*Pointeur vers le fichier que l'on va envoyer au récepteur*/ /*Contrôle du nombre d'arguments*/ if (argc != 3) { printf("\nUsage: ./%s IPrecepteur NumPort\n", argv[0]); exit(1); } /*Création de la socket de l'émetteur*/ emetteur = creeSocket(atoi(argv[2])); if(emetteur<0) { perror("Erreur création socket"); } /*Construction de l'adresse du récepteur*/ receveur.sin_family = AF_INET; receveur.sin_port = htons(SERVEUR_PORT); h = gethostbyname(argv[1]); if (h == NULL) { perror("Erreur gethostbyname\n"); exit(1); } ip_receveur = (struct in_addr *)h->h_addr_list[0]; printf("\n Adresse ip du receveur est: %s\n",inet_ntoa(*ip_receveur)); inet_ntoa(*ip_receveur); memcpy((char*)(&receveur.sin_addr.s_addr), h->h_addr_list[0], h->h_length); /*Envoi du fichier au récepteur*/ while(fgets(ligne,MAX_BUF,fichier)!=NULL) { /*On note ici que le seul changement par rapport à un envoi UDP "classique" est l'appel à la fonction "envoi" au lieu de "sendto"*/ if (envoi(emetteur,ligne,strlen(ligne),0,(struct sockaddr_in *)&receveur, sizeof(receveur)) < 0) { perror (argv[0]); exit(1); } else { printf("Envoi à %s sur le port %d:\n",inet_ntoa(receveur.sin_addr),receveur.sin_port); printf("%s\n",ligne); /*Tentative de réception d'un ack*/ reception (emetteur, bufreception, MAX_BUF, 0, (struct sockaddr_in *)&receveur, sizeof(receveur)); /*printf("Reçu %s\n", bufreception);*/ } } /*Fermeture de la socket et du fichier*/ close (emetteur); fclose(fichier); return 0; }
CODE DES FONCTIONS ENVOI/RECEPTION
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 /******************************************************* Nom ......... : Serveur.c Role ........ : Serveur UDP Compilation : make all ********************************************************/ #include "librairies.h" #include "socket.h" #define DEBUG_MODE int main(int argc, char *argv[]) { /*Variables*/ int receveur; /*descripteur du socket du receveur*/ char bufreception[MAX_BUF]; int ret_reception;/*pour la réception de paquets*/ char bufenvoi[MAX_BUF]; int ret_envoi;/*pour l'envoi de paquets*/ struct sockaddr_in emetteur;/*adresse de l'émetteur (client qui viendra se connecter)*/ time_t temps;/*stockage d'une date*/ FILE *log; strncpy(bufreception,"",strlen(bufreception)) ; /*Contrôle du nombre d'arguments*/ if (argc != 2) { printf("\nUsage: ./%s numPort\n", argv[0]); exit(1); } /*Construction fichier de log*/ log=fopen("log.txt","w+"); if(log==NULL) { perror("Erreur d'accès au fichier 'log.txt', l'archivage sur cette session n'est pas géré\n"); } time(&temps); fprintf(log," -------------------------------------------------\n"); fprintf(log,"| Ce fichier contient l'historique des connexions |\n"); fprintf(log," -------------------------------------------------\n"); fprintf(log," Date de creation: %s \n ", ctime(&temps)); /*Création de la socket du receveur*/ receveur=creeSocket(atoi(argv[1])); fprintf(log, "Creation d'une socket sur le port %d... \n",atoi(argv[1])); #ifdef DEBUG_MODE printf("Creation d'une socket sur le port %d... \n",atoi(argv[1])); #endif /*Boucle infinie de réception des messages de l'émetteur*/ while(1) { fflush(stdout); ret_reception=reception(receveur, bufreception,MAX_BUF,0, (struct sockaddr_in*)&emetteur, sizeof(emetteur)); if (ret_reception<0) { perror("Erreur réception du paquet\n"); exit(1); } /*Récupération des infos de l'émetteur*/ printf("Réception d'un message de : %s:%u\n",inet_ntoa(emetteur.sin_addr),ntohs(emetteur.sin_port)); time(&temps); fprintf(log, "\n Une demande de connexion est recue:\n"); fprintf(log, "\t * Date de connexion: %s", ctime(&temps)); fprintf(log, "\t * Famille du Socket client: %x\n", ntohs(emetteur.sin_family)); fprintf(log, "\t * Port client: %u\n", ntohs(emetteur.sin_port)); fprintf(log, "\t * IP client: %s\n", inet_ntoa(emetteur.sin_addr)); /*Traitement du paquet reçu*/ printf("Contenu du paquet :\n\t%s\n",bufreception); fprintf(log, "Contenu du paquet : \n"); fprintf(log, "\t%s\n",bufreception); /*Réinitialisation du buffer de réception*/ strncpy(bufreception,"",strlen(bufreception)) ; strncpy(bufenvoi,"hi",strlen(bufenvoi)) ; sleep(3);/*Pour test*/ envoi(receveur,bufenvoi,MAX_BUF,0,(struct sockaddr_in*)&emetteur, sizeof(emetteur)); } /*Fermeture des sockets/fichiers ouverts*/ fclose(log); close(receveur); return 0; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 #include "rtt.h" #include "socket.h" #define DEBUG_MODE /*Variables*/ uint32_t recentsequence; /*Dernier numéro de séquence acquitté*/ static struct msghdr msgenvoi, msgreception; /*Structure despaquets à envoyer/recevoir*/ static struct header { /*Structure des informations complémentaires à joindre dans nos paquets*/ int type; /*0 pour les data, 1 pour les ack*/ uint32_t sequence; /*Numéro de séquence*/ uint32_t ack; /*Acquittement du dernier numéro de séquence reçu*/ /*uint32_t ack_precedents; Bits d'acquittements des 32 derniers paquets*/ } envoihdr, receptionhdr; /*Fin déclaration variables*/ /*Fonction d'envoi d'un paquet de manière fiable que send*/ ssize_t envoi(int sockfd, void *buf, size_t len, int flags, struct sockaddr_in *dest_addr, socklen_t addrlen) { int n;/*retour de la fonction 'sendmsg'*/ /*Phase 1 : Préparation des nouvelles données du paquet constituées du nouvel header et des données à envoyer*/ struct iovec iovenvoi[2];/*Une structure iovec va être remplie avec : - Un pointeur vers des données, - La taille de ces données*/ iovenvoi[0].iov_base=&envoihdr;/*pointeur vers données[0] : intégration du nouvel header*/ iovenvoi[0].iov_len=sizeof(struct header);/*taille des données[0] : taille du nouvel header*/ iovenvoi[1].iov_base=buf;/*pointeur vers données[1] : intégration des données à envoyer*/ iovenvoi[1].iov_len=len;/*taille des données[1] : taille des données*/ /*Remplissage du header*/ envoihdr.sequence++; envoihdr.type=0; envoihdr.ack=recentsequence; /*Phase 2 : Création d'un nouveau paquet*/ msgenvoi.msg_name=dest_addr; msgenvoi.msg_namelen=addrlen; /*Phase 3 : Intégration des données au paquet*/ msgenvoi.msg_iov=iovenvoi; msgenvoi.msg_iovlen=2; #ifdef DEBUG_MODE fprintf(stderr, "\nEnvoi du paquet :%4d\n",envoihdr.sequence); #endif n=sendmsg(sockfd, &msgenvoi,0); return (n-sizeof(struct header)); } /*Fonction de réception d'un paquet de manière plus fiable que recv*/ ssize_t reception(int sockfd, void *buf, size_t len, int flags, struct sockaddr_in *src_addr, socklen_t *addrlen) { /*Variables*/ ssize_t n; struct iovec iovreception[2]; /*select*/ int ret = 0; fd_set readfs; char* msgbufreception; /*Préparation du paquet*/ msgreception.msg_name=NULL; msgreception.msg_namelen=0; msgreception.msg_iov=iovreception; msgreception.msg_iovlen=2; iovreception[0].iov_base=&receptionhdr; iovreception[0].iov_len=sizeof(struct header); iovreception[1].iov_base=buf; iovreception[1].iov_len=len; n=recvmsg(sockfd,&msgreception,0); #ifdef DEBUG_MODE fprintf(stderr, "Reçu paquet num séquence :%4d\n", receptionhdr.sequence); #endif /*Comparaison du numéro de séquence du paquet reçu avec la variable recentsequence, et mise à jour de cette variable si nécessaire*/ if(receptionhdr.sequence > recentsequence) { recentsequence=receptionhdr.sequence; } return(n - sizeof(struct header));/*Retourne la taille du datagramme reçu*/ }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 int creeSocket(int numPort) { struct sockaddr_in servAddr; int sd; /*descripteur du socket*/ int reuse=1; /*Création de la socket*/ if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("Erreur création de socket\n"); exit(1); } servAddr.sin_family = AF_INET; servAddr.sin_addr.s_addr = htonl(INADDR_ANY); servAddr.sin_port = htons(numPort); /*Attachement de la socket à une addresse et un port*/ if (bind(sd,(struct sockaddr*) &servAddr, sizeof(servAddr)) < 0) { perror("Erreur bind socket\n"); exit(1); } /*Pour libération de la socket après close()*/ if(setsockopt(sd,SOL_SOCKET, SO_REUSEADDR, (int *)&reuse, sizeof(reuse))==-1) { perror("Erreur SO_REUSEADDR"); } #ifdef DEBUG_MODE printf("Socket créée\n"); #endif return sd; }
Partager