Annonce

Rduire
Aucune annonce.

[RSOLU]Mini-chat en C, problme recv.

Rduire
X
 
  • Filtre
  • Heure
  • Afficher
Tout nettoyer
nouveaux messages

  • [RSOLU]Mini-chat en C, problme recv.

    Bonjour,

    Je vous crit pour avoir de votre aide sur un projet personnel.
    Un "simple" mini-chat en C.

    J'y ai ajout une fonction pour rcuprer un fichier texte.
    N'ayant pas trouv d'aide sur internet, ou du moins pas suffisante, j'ai du me dbrouiller pour construire le systme.

    Aprs quelques jours de casse-tte, j'ai finalement russi crer ce que je voulais.
    Brivement, le client suite la rception d'une commande que j'envoie via le serveur, va compter le nombre de caractres dans un fichier [prcis], puis le diviser en X blocs, sachant qu'un bloc est gal 1024 caractres, 2 blocs = 2048 etc...

    Je reois tout normalement, ou presque, quand les caractres envoys par blocs sont reus (par le serveur), il y a la commande (RECUP) qui se rajoute chaque fin de bloc.

    Par exemple :

    Serveur >> recup //Commande
    Client << 2 //Nombre de blocs.
    Client << [BLOC de 1024 caractres]recup //Notez le recup en plus.
    Client << [Dernier bloc de 120 caractres] //Pour le dernier bloc, il n'y a pas le recup qui vient s'ajouter.

    J'ai touch un peu tout, sans vraiment s'avoir d'ou cela pouvait venir. Aucune piste pour l'instant, mais je souponne la longueur envoy en send et recv.
    Sachant que les deux sont 1024.

    Bref, voici le code CLIENT :

    Code:
    else if(strstr(bufferRecv, code_recv)){ //Si le message reu est gal  "RECUP"
                            int bclsnd = 0; //Boucle while
                            int plus = 0; //Pour les blocs  envoyer.
                            char bufnbr[10]; //Variable pour envoyer le nombre de bloc au seveur.
                            FILE* checkf = NULL;
                            checkf = fopen(path, "r"); //Vrifie que checkf (fichier texte) existe.
                            if (checkf!=NULL){ //Si aucune erreur alors
                                fclose(checkf); //Fermeture de checkf
                                CountChar(); //Va dans une fonction pour calculer le nombre de caractres & blocs.
                                sprintf(bufnbr, "%d", nbrsend); //Stock un int dans un char.
                                send(sock, bufnbr, 10, 0); //Envoi du int stock dans un char.
                                while(bclsnd != nbrsend){ //Boucle pour l'envoi des blocs.
                                    send(sock, text_log+plus, 1024, 0);
                                    plus += 1024; //Se tlporte 1024 caractres plus loin pour envoyer les blocs.
                                    ++bclsnd;
                                    }
                                }
                            else { //Si checkf (fichier texte) n'existe pas alors.
                                send(sock, text_return[1], 20, 0); //Envoi d'une erreur
                            }
                        }
    Le ct SERVEUR :

    Code:
    else if (strstr(bufferSend, code_recv)){ //Si le message envoy est gal  "RECUP"
                            int bclrcv = 0; //Variable pour boucle while
                            int client_id = atoi(bufferRecv); //Rcupre le message client (CHAR) et le converti en INT.
                                while(bclrcv != client_id){ //Boucle pour recevoir les blocs.
                                    recv(csock, bufferRecv, 1024, 0); //Rception du premier bloc de 1024 caractres.
                                    printf("Client >> %s\n",bufferRecv); //Affiche le bloc.
                                    stock(bufferRecv); //Stock le bloc pour le reconstituer.
                                    ++bclrcv;
                                }
                        }
    Voici le contenu du fichier texte :

    Code:
    DEBUT_AAAAAAAAAA_FIN
    Le A est prsent 2160 fois, je ne l'ai pas directement C/C pour des raisons videntes.

    Et pour finir, voici ce que je reois :

    A gauche le serveur ou j'y envois la commande "RECUP" qui demande au client d'envoyer le contenu du fichier texte.
    A droite le contenu du fichier texte est affich pour montrer qu'il n'est de base, pas corrompu.

    Les blocs sont ensuite reconstitus, et voici le rsultat :

    Code:
    DEBUT_AAAAA
    recup
    AAAAA
    recup
    AAAAA_FIN
    Il devrait s'afficher ainsi :

    Code:
    DEBUT_AAAAAAAAAAAAAAA_FIN
    Une fois encore, c'est raccourci, j'espre que a reste tout de mme comprhensible.
    Notez tout de mme que le recup provoque un saut de ligne...

    Quand le fichier texte fait moins de 1024 caractres, je n'ai pas faire face ce problme. Ni la fonction de reconstitution des blocs [SERVEUR] ni le calcul des blocs & des caractres [CLIENT] n'est remettre en cause.
    J'espre avoir de l'aide, j'en ai grandement besoin !

    Amicalement,
    Dernire modification par fred, 27 juillet 2015, 13h03.

  • #2
    Salut

    Effectivement avec les sockets en C tu peux avoir des difficults si ton message dpasse la taille du buffer utilis (1024 dans ton cas)

    else if (strstr(bufferSend, code_recv[7])){ //Si le message envoy est gal "RECUP"
    int bclrcv = 0; //Variable pour boucle while
    int client_id = atoi(bufferRecv); //Rcupre le message client (CHAR) et le converti en INT.
    while(bclrcv != client_id){ //Boucle pour recevoir les blocs.
    recv(csock, bufferRecv, 1024, 0); //Rception du premier bloc de 1024 caractres.
    printf("Client >> %s\n",bufferRecv); //Affiche le bloc.
    stock(bufferRecv); //Stock le bloc pour le reconstituer.
    ++bclrcv;
    }
    }

    Je ne vois pas pourquoi tu utilise un id pour le client.
    A mon avis le plus simple serait de faire un serveur, qui attend la connexion de 2 clients. Une fois que les deux sont connects chaque client peut envoyer un message au serveur qui sera renvoy vers le second client.

    Si tu n'a jamais manipul de socket le plus simple serait de commencer par faire un programme qui fonctionne avec un ordre prcis :
    Le serveur attend 2 client
    1 client se connecte -> client1
    1 autre se connecte -> client2
    le serveur attend 1 message de client1
    quand le message arrive il le renvoie client 2
    le serveur attend un message de client2
    Puis il le renvoie client1 quand il l'a recu.

    Le tout en boucle pour envoyer plusieurs messages
    Une fois que ca marche tu peux passer aux sockets non bloquantes (avec la fonction ioctl() par exemple) pour que les clients puissent envoyer des messages dans n'importe quel ordre, voir en mme temps

    Et si tu veux encore amliorer tu peux ajouter un multithread pour grer plusieurs conversations en mme temps

    Si tu veux juste faire un transfert de fichier et pas un chat comme le titre l'indique, tu n'as pas besoin d'envoyer une commande rcup.
    Par dfaut une socket est bloquante, c'est dire que lorsque le serveur arrive sur les fonctions select(), recv()... il se contente d'attendre d'avoir de l'activit sur la socket (il sera dbloqu une premire fois au moment de la connexion d'un client, puis en recevant un message)


    En gros ton serveur doit se contenter d'attendre une connexion de la part d'un client, puis en boucle il attend des donnes sur la socket.
    Il va bloqu sur recv, recevoir une partie du message, le stocker ailleurs, de prfrence dans un fichier dans ton cas, (eventuellement vider le buffer pour viter les problmes) et nouveau bloqu sur recv tant qu'il est dans la boucle. Et tu n'as plus qu'a quitter la boucle quand tu ne reoit plus de donnes

    au niveau du client tu dois te connecter au serveur, et envoyer des donnes en boucle de la mme faon, en quittant ta boucle quand ton fichier a t entirement parcouru

    Ca te permet d'amliorer ton programme (au niveau de la performence et de ta capacit l'amliorer plus tard), en contournant les problmes poss par le fait de demander l'envoie du fichier par le serveur, et tu n'a pas besoin d'id de client (la socket identifie dja la connexion de faon unique grce aux noms des machines et au port utilis)



    EDIT : au fait n'oublie pas qu'en c une chaine est sense se terminer par le caractre '\0' qui n'est pas affich avec ta chane mais qui utilisera un caractre dans ton tableau
    Dernire modification par oliver39, 25 juillet 2015, 10h15.

    Commentaire


    • #3
      Code:
      else if(strstr(bufferRecv, code_recv[7]))
      Il y a une erreur flagrande, code_recv[7] retournera un caractre, non un tableau de chars, ce dont a besoin la fonction strstr...

      Il faudra modifier pour

      Code:
      else if(strstr(bufferRecv, code_recv))
      Je n'ai pas regard la suite, mais j'espre que tu fais cela pour t'entraner en C, car sinon je ne vois pas l'intrt de faire cela en C, j'aurais choisi plutt python, ou autres langages de scripts...

      Commentaire


      • #4
        Bonjour Olivier et merci de ta rponse,

        Le client_id n'est rien d'autre que la variable qui recevra le nombre de blocs.
        Je n'ai pas mis le code en entier, c'est bel et bien un mini-chat, ou le client peut communiquer avec le serveur et vice-versa.

        Si tu n'a jamais manipul de socket le plus simple serait de commencer par faire un programme qui fonctionne avec un ordre prcis :
        Le serveur attend 2 client
        1 client se connecte -> client1
        1 autre se connecte -> client2
        le serveur attend 1 message de client1
        quand le message arrive il le renvoie client 2
        le serveur attend un message de client2
        Puis il le renvoie client1 quand il l'a recu.
        Ce projet est le premier qui manipule les sockets, mon exprience dans ce domaine est trs limite.
        Le serveur est programm pour ne communiquer qu'avec un client, tout est dj fonctionnel sur la connexion, l'attente d'une connexion, l'attente d'un message, l'envoi etc...

        J'ai dj entendu parler des sockets non bloquantes, mais je ne me suis pas encore vraiment pench sur le sujet. Est-ce que mon programme en a forcment besoin ? Les fonctions qui reoivent et envoient les blocs fonctionnent pour le moment relativement bien. Le serveur a bien compris qu'il allait devoir attendre X messages de la part du client et le client a lui aussi compris qu'il devait envoyer une srie de messages.

        Il est tout de mme vrai que ce n'est pas un chat part entire, puisque que le serveur ne peut rien faire tant qu'il n'a pas reu une rponse du client. Mais c'est justement le but recherch, je souhaite que tout soit "contrl" et "encadr".
        Chacun son tour.

        Si tu veux juste faire un transfert de fichier et pas un chat comme le titre l'indique, tu n'as pas besoin d'envoyer une commande rcup.
        La commande recup est superficielle, vrai dire, je pourrais envoyer le fichier texte directement quand il y a la connexion du client, mais ce n'est pas ce que je souhaite faire.

        En gros ton serveur doit se contenter d'attendre une connexion de la part d'un client, puis en boucle il attend des donnes sur la socket.
        Il va bloqu sur recv, recevoir une partie du message, le stocker ailleurs, de prfrence dans un fichier dans ton cas, (eventuellement vider le buffer pour viter les problmes) et nouveau bloqu sur recv tant qu'il est dans la boucle. Et tu n'as plus qu'a quitter la boucle quand tu ne reoit plus de donnes

        au niveau du client tu dois te connecter au serveur, et envoyer des donnes en boucle de la mme faon, en quittant ta boucle quand ton fichier a t entirement parcouru
        C'est exactement ce que j'ai tent de faire via les 2 fonctions que j'ai mis sur le premier post...
        Peut-tre que je m'y suis mal pris.

        Commentaire


        • #5
          Envoy par fred Voir le message
          Il y a une erreur flagrande, code_recv[7] retournera un caractre, non un tableau de chars, ce dont a besoin la fonction strstr...

          Il faudra modifier pour

          Code:
          else if(strstr(bufferRecv, code_recv))
          Je n'ai pas regard la suite, mais j'espre que tu fais cela pour t'entraner en C, car sinon je ne vois pas l'intrt de faire cela en C, j'aurais choisi plutt python, ou autres langages de scripts...
          En effet, petite erreur, je corrige.
          Oui je fais a pour m'entraner, c'est le but premier de ce programme, je ne compte ni le distribuer, ni l'utiliser.
          J'avoue tre plus attir par le C que par le python...

          Commentaire


          • #6
            En effet, petite erreur, je corrige.
            Oui mais n'y a-t-il pas d'impact sur l'excution de ton code ? Grce cette correction tu dois pouvoir entrer dans le if normalement!

            Commentaire


            • #7
              Envoy par fred Voir le message
              Oui mais n'y a-t-il pas d'impact sur l'excution de ton code ? Grce cette correction tu dois pouvoir entrer dans le if normalement!
              J'ai du le rajouter accidentellement pendant l'criture du sujet, dans le projet je ne l'ai pas.
              Dernire modification par Hookel, 25 juillet 2015, 11h19.

              Commentaire


              • #8
                Si tu veux juste recevoir le texte de ton fichier

                Client

                File *f = fopen(...)
                if (f == NULL) {
                //erreur
                //fermeture connexion (shutdown(...) et close(...))
                //return pour stopper l'excution de ta fonction
                }
                while (//la lecture du fichier n'est pas termine) {
                buff = Lecture de x octets //(le nombre que tu veux envoyer)
                send (sock, buff, ...)
                buff += x //x est le nombre d'octets lus chaque fois pour passer la suite du fichier
                }
                //fermeture connexion


                Pour le serveur tu n'as qu'a rcuprer les infos envoyes sur la socket et les afficher (et ventuellement les stocker dans un fichier)


                Un code dans ce genre la devrait fonctionner (je te laisse traduire ca en C)


                ps : dans ton client comment la variable text_log est affecte? et quand tu envoie le nombre de block je te conseille d'utilise sizeof(int) au lieu de 10 et pareil dans la rception de ton message
                idem pour envoyer les chaines dclare un buffer de 1024 et envoie sizeof(buffer)
                Dernire modification par oliver39, 25 juillet 2015, 12h11.

                Commentaire


                • #9
                  Code:
                  send(sock, text_log+plus, 1024, 0);
                  Il y a sans doute une erreur ici aussi, je crois que tu n'as pas tout compris dans l'arithmtique des pointeurs...

                  Voici un exemple

                  Code:
                  #include <stdio.h>
                  
                  int main(void){
                  
                      char bloc[] = "abcdefghijklmnopqrstuvwxyz";
                      char *p;
                  
                      for (p=bloc; *p!='\0'; p+=2)
                          printf("%s\n", p);
                  
                      return 0;
                  }
                  
                  /* lecture redondante */
                  /*
                  abcdefghijklmnopqrstuvwxyz
                  cdefghijklmnopqrstuvwxyz
                  efghijklmnopqrstuvwxyz
                  ghijklmnopqrstuvwxyz
                  ijklmnopqrstuvwxyz
                  klmnopqrstuvwxyz
                  mnopqrstuvwxyz
                  opqrstuvwxyz
                  qrstuvwxyz
                  stuvwxyz
                  uvwxyz
                  wxyz
                  yz
                  */
                  Alors que toi tu aurais souhait je pense

                  Code:
                  ab
                  cd
                  ef
                  gh
                  ij
                  kl
                  mn
                  op
                  qr
                  st
                  uv
                  wx
                  yz
                  Du coup on peut modifier le code ainsi

                  Code:
                  #include <stdio.h>
                  #include <string.h>
                  
                  #define TAILLE_BLOC 2
                  
                  int main(void){
                  
                      char bloc[] = "abcdefghijklmnopqrstuvwxyz";
                      char *p;
                      char res[TAILLE_BLOC+1];
                  
                      for (p=bloc; *p!='\0'; p+=TAILLE_BLOC){
                          strncpy(res, p, TAILLE_BLOC);
                          printf("%s\n", res);
                      }
                  
                      return 0;
                  }

                  Commentaire


                  • #10
                    Bonjour !

                    Je pense avoir enfin rsolu le problme, notamment grce au code de Fred. Je l'ai lgrement "bidouill" pour l'adapter au programme.
                    La partie aussi qui comptait les caractres et le nombre de blocs avait aussi un petit problme, il est maintenant rgl.

                    Mais, il est vrai que :

                    Code:
                    send(sock, text_log+plus, 1024, 0);
                    plus += 1024;
                    N'est surement pas la plus propre des mthodes. J'ai utilis cette pseudo technique aprs l'avoir vue sur un code trouv sur un forum.
                    Malheureusement, je ne comprends toujours pas pourquoi je recevais pourtant le code dans son entiret... Mystre.

                    Bref, le casse-tte tant rgl je vous remercie de m'avoir conseill, olivier & fred !

                    Bonne journe vous,

                    Commentaire


                    • #11
                      Bonjour,

                      Content d'avoir aid, n'hsites pas utiliser le bouton Thanks (en bas gauche de chaque topic) quand un topic t'as aid particulirement...

                      Bonne journe

                      Commentaire


                      • #12
                        J'en ai oubli les bonnes manires... Les remerciements ont t donn.

                        Dommage par contre qu'il n'y a pas une fonction rsolu.

                        Commentaire


                        • #13
                          Dommage par contre qu'il n'y a pas une fonction rsolu.
                          Effectivement, mais je vais diter le titre pour que se soit clairement exprim !

                          Commentaire

                          Chargement...
                          X