IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Réseau C Discussion :

Client / Serveur en local


Sujet :

Réseau C

  1. #1
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2011
    Messages
    754
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Août 2011
    Messages : 754
    Points : 376
    Points
    376
    Par défaut Client / Serveur en local
    Bonsoir,

    , j'aurais quelque questions à vous poser

    j'ai ici deux codes un pour un client et un pour un serveur, les deux fonctionnant en local.

    L'idée étant que le client veut envoyer un message au serveur.
    Le serveur renvoie alors ce même message au client.
    Le client affiche le message reçu.

    Concrètement il s'agit de voir si le message est toujours intact après deux échanges. C--->S---> C



    Ce que j'ai pu remarquer à présent avec mon code, c'est que le message envoyé par C arrive bien au serveur, l'affichage me le confirme.

    En revanche, le client n'a pas toujours le temps de récupérer à nouveau le message qui est aléatoirement, correct ou incomplet.

    J'ai supposé que cela était dû au serveur qui, après avoir envoyé de nouveau le message n'attends pas.

    S'il n'attends pas, alors soit le message est lu assez tôt par le client, soit il n'a pas été lu assez tôt, auquel cas le serveur se termine et du coup il est impossible au client de récupérer son message.


    J'aimerais donc arriver à modifier le code suivant pour avoir un échange complet; peut être en ajoutant une sorte d'acquittement ? Mais j'avoue ne pas voir comment faire ?

    Un coup de main serait apprécié

    Client.c

    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
     
    int main(int argc, char *argv[]) {
        int portno, sockfd;
        struct sockaddr_in serv_addr;
        struct hostent *server;
     
        char *msg="Message d'exemple";
     
        portno = 7000;
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) 
            error("ERROR opening socket");
        server = gethostbyname("localhost");
        if (server == NULL) {
            fprintf(stderr,"ERROR, no such host\n");
            exit(0);
        }
     
        bzero((char *) &serv_addr, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        bcopy((char *)server->h_addr, 
             (char *)&serv_addr.sin_addr.s_addr,
             server->h_length);
        serv_addr.sin_port = htons(portno);
        if (connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) 
            error("ERROR connecting");
     
        char *buffer=malloc(sizeof(char)*(strlen(msg)+1));
     
        write(sockfd,msg,strlen(msg));
        read(sockfd,buffer,strlen(msg));
     
        // On reçoit un tableau de char on converti en string en ajoutant \0
        buffer[strlen(msg)]='\0';
        printf("%s\n", buffer);
     
        return 0;

    Serveur.c

    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
     
    int main(int argc, char *argv[])
    {
         int sockfd, newsockfd, portno, clilen;
         char buffer;
         struct sockaddr_in serv_addr, cli_addr;
         int n;
     
         sockfd = socket(AF_INET, SOCK_STREAM, 0);
         if (sockfd < 0) 
            error("ERROR opening socket");
         portno = 7000;
         serv_addr.sin_family = AF_INET;
         serv_addr.sin_addr.s_addr = INADDR_ANY;
         serv_addr.sin_port = htons(portno);
         if (bind(sockfd, (struct sockaddr *) &serv_addr,
                  sizeof(serv_addr)) < 0) 
                  error("ERROR on binding");
         listen(sockfd,5);
         clilen = sizeof(cli_addr);
     
         newsockfd = accept(sockfd, 
                     (struct sockaddr *) &cli_addr, 
    			(socklen_t*) &clilen);
         if (newsockfd < 0) 
              error("ERROR on accept");
     
         do {
           n = read(newsockfd,&buffer,1);
           write(newsockfd,&buffer, 1);
         } while(n>-1);
     
         return 0; 
    }
    En gros, il faudrait que mon serveur soit capable d'attendre après avoir écris dans la socket que le client est bien reçu avant de fermer la socket. Si j'avais un main unique, j'aurais pu simuler ça avec des tubes et des process assez facilement; mais là je vois pas du tout comment je peux faire.


    Merci à vous !!

  2. #2
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut
    Bonjour,

    Dans le client comme dans le serveur, tu fais les actions de read et write immédiatement les unes après les autres... Pourquoi ?

    Dans le client, tu fais un write sur sockfd, et immédiatement un read sur cette socket. Ne serait-ce pas au serveur de faire ce read ?
    Dans le serveur, tu fais bien un read dans une boucle, pour lire tant qu'il y a des choses à lire. Mais pourquoi les écrire immédiatement ?
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  3. #3
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    Citation Envoyé par gangsoleil Voir le message
    Dans le serveur, tu fais bien un read dans une boucle, pour lire tant qu'il y a des choses à lire. Mais pourquoi les écrire immédiatement ?
    pour la 1ère passe j'imagine, de manière à renvoyer le message, c'est plutôt la boucle qui est superflue j'ai l'impression, il aurait pu se contenter d'un read/write/read en gros, m'est avis.

    @Amnael, je me suis pas penché en détail sur ton code mais y'a au moins 2 points sur lesquels j'investiguerai à ta place
    • le fait d'utiliser read et write, même si c'est censé fonctionner les syscalls pour envoyer et recevoir des données sur le réseau sont plutôt sendmsg et recvmsg
    • tu ne clos pas la socket explicitement


    Citation Envoyé par Amnael Voir le message
    peut être en ajoutant une sorte d'acquittement ?
    non, tu es en TCP, les acquittements sont gérés automatiquement par le protocole, mon sentiment c'est qu'une fermeture de socket explicite pourrait peut-être aider, à vérifier néanmoins

    Edit:
    je viens de tester le code (sur une VM 32bits) en l'état (modulo les includes et la fonction error() faite maison), je n'ai aucun problème particulier, le code semble fonctionner comme attendu
    ci joint la capture (tcpdump, filtrée/gzippée par wireshark, lisible telle que par wireshark) du trafic réseau, on note la fin de connexion brutale comme prévu également, mais le message transite correctement
    Fichiers attachés Fichiers attachés

  4. #4
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2011
    Messages
    754
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Août 2011
    Messages : 754
    Points : 376
    Points
    376
    Par défaut
    En fait, ce code est donné tel quel en tant que source d'un projet

    Il est tout à fait fonctionnel pour la partie client qui envoie des informations au serveur. ==> serveur reçoit toujours le message complet.

    C'est simplement que, le serveur ferme PARFOIS sa connexion avant d'avoir renvoyé les données au client. Ce qui résulte avec le fait que le serveur ne reçoive pas toujours la totalité du message du serveur.

    Je suis aussi d'accord, il serait bien plus propre de clore la socket à la fin; mais d'après ce que j'ai compris, on doit pouvoir dans un premier temps faire des modifications sur ce code pour empêcher le problème que j'ai mentionné plus haut.


    En gros si j'exécute plusieurs fois, il se peut très bien que la première fois je reçoive bien "Message d'exemple" sur mon client; mais il se peut aussi que je reçoive "Me". Ceci de façon aléatoire complètement.


    Je veux bien rajouter un close sur ma socket, ce sera plus propre, mais ça ne changera rien au problème, il faudrait que je puisse dire à mon serveur: attends que le client est reçu le message pour fermer ta socket. D'où mon idée d'acquittement.

    Mais acquittement n'est pas vraiment le bon terme ici, il s'agirait plutôt de trouver un moyen pour que client dise à serveur...ok j'ai plus rien à t'envoyer donc tu peux fermer la socket maintenant. Et tant que le serveur n'a pas reçu ce "signal" il ne pourra pas fermer la socket.



    C'est ce fameux signal que je ne sais pas comment implémenter, j'aurais pu le simuler avec deux process en multi tâche, mais là, un signal émis par mon client ne sera pas capturé par le serveur. Malheureusement, hormis le fait de faire communiquer deux process en parallèles avec des signaux je ne vois aucun moyen de faire ça...

  5. #5
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut
    Bonjour,

    Il est impossible de prevoir combien d'octets vont être envoyés via un send, ou combien vont être lus via un recv, et c'est pour ça que lorsqu'on veut être certain de travailler sur N caractères, on met ces fonctions dans une boucle qui itérera jusqu'à ce que tout soit lu/écrit.

    Si tu mets tes read/write dans des boucles indépendantes, cela devrait donc t'aider.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  6. #6
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2011
    Messages
    754
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Août 2011
    Messages : 754
    Points : 376
    Points
    376
    Par défaut
    Donc en fait, coté serveur on va stocker l'ensemble des caractères qui seront lu avant de les renvoyer. Je ne suis pas certain d'avoir le droit de modifier le fait que j'écrive juste après la lecture caractère par caractère.

    Je vais me renseigner. Merci !

  7. #7
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    Citation Envoyé par Amnael Voir le message
    C'est simplement que, le serveur ferme PARFOIS sa connexion avant d'avoir renvoyé les données au client. Ce qui résulte avec le fait que le serveur ne reçoive pas toujours la totalité du message du serveur.
    ok effectivement j'avais pas cogité ça dans ce sens, au temps pour moi

    il faudrait que je puisse dire à mon serveur: attends que le client est reçu le message pour fermer ta socket.
    en remplaçant uniquement dans le client le read par recv(sockfd, buffer, strlen(msg), MSG_WAITALL); tout semble fonctionner, à vérifier
    (intrusif au minimum dans le code original)

Discussions similaires

  1. Réponses: 8
    Dernier message: 10/03/2015, 21h39
  2. Transformation de code local à une applet(client/serveur)
    Par Amjad Ayadi dans le forum Tomcat et TomEE
    Réponses: 0
    Dernier message: 22/04/2009, 00h16
  3. Réponses: 1
    Dernier message: 19/09/2008, 09h29
  4. appli client/serveur de chat en local
    Par yorukaze dans le forum Entrée/Sortie
    Réponses: 6
    Dernier message: 05/02/2008, 11h12
  5. Client/Serveur en Local sans connexion réseau
    Par ramoud dans le forum C++Builder
    Réponses: 8
    Dernier message: 05/07/2007, 14h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo