Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 2 sur 2
  1. #1
    Membre du Club Avatar de tenebriox
    Profil pro Flo
    Inscrit en
    juin 2009
    Messages
    88
    Détails du profil
    Informations personnelles :
    Nom : Flo

    Informations forums :
    Inscription : juin 2009
    Messages : 88
    Points : 69
    Points
    69

    Par défaut Blocage recvmsg (client/serveur udp)

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

  2. #2
    Membre du Club
    Profil pro Ghislain AUTRET
    Ingénieur développement logiciels
    Inscrit en
    janvier 2004
    Messages
    54
    Détails du profil
    Informations personnelles :
    Nom : Ghislain AUTRET
    Localisation : Réunion

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2004
    Messages : 54
    Points : 46
    Points
    46

    Par défaut

    Salut,

    As tu essayé de voir ce qui se passe avec wireshark?
    le récepteur reçoit-il bien le message en entier?
    Enoie-t-il bien le ack à l'émetteur?
    que font tes fonction rcvmsg() et sendmsg()?

    Par défaut le rcv est bloquant, on utilise select() pour vérifier qu'on a des données sur la socket avant de faire un rcv.

    voilà quelques pistes.
    Au paradis, on est assis à la droite de Dieu.
    C'est normal, c'est la place du mort
    - [Pierre Desproges]

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •