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 : 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 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
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 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
 
#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;
}