Annonce

Réduire
Aucune annonce.

[RÉSOLU]Mini-chat en C, problème recv.

Réduire
X
 
  • Filtre
  • Heure
  • Afficher
Tout nettoyer
nouveaux messages

  • [RÉSOLU]Mini-chat en C, problème 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 récupérer un fichier texte.
    N'ayant pas trouvé d'aide sur internet, ou du moins pas suffisante, j'ai du me débrouiller pour construire le système.

    Après quelques jours de casse-tête, j'ai finalement réussi à créer ce que je voulais.
    Brièvement, le client suite à la réception d'une commande que j'envoie via le serveur, va compter le nombre de caractères dans un fichier [précis], puis le diviser en X blocs, sachant qu'un bloc est égal à 1024 caractères, 2 blocs = 2048 etc...

    Je reçois tout normalement, ou presque, quand les caractères envoyés par blocs sont reçus (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 caractères]recup //Notez le recup en plus.
    Client << [Dernier bloc de 120 caractères] //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 soupçonne 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 reçu 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"); //Vérifie 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 caractères & 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 téléporte 1024 caractères 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 côté 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); //Récupère le message client (CHAR) et le converti en INT.
                                while(bclrcv != client_id){ //Boucle pour recevoir les blocs.
                                    recv(csock, bufferRecv, 1024, 0); //Réception du premier bloc de 1024 caractères.
                                    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 présent 2160 fois, je ne l'ai pas directement C/C pour des raisons évidentes.

    Et pour finir, voici ce que je reçois :

    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 reconstitués, et voici le résultat :

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

    Code:
    DEBUT_AAAAAAAAAAAAAAA_FIN
    Une fois encore, c'est raccourci, j'espère que ça reste tout de même compréhensible.
    Notez tout de même que le recup provoque un saut de ligne...

    Quand le fichier texte fait moins de 1024 caractères, je n'ai pas à faire face à ce problème. Ni la fonction de reconstitution des blocs [SERVEUR] ni le calcul des blocs & des caractères [CLIENT] n'est à remettre en cause.
    J'espère avoir de l'aide, j'en ai grandement besoin !

    Amicalement,
    Dernière modification par fred, 27 juillet 2015, 13h03.

  • #2
    Salut

    Effectivement avec les sockets en C tu peux avoir des difficultés si ton message dépasse 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); //Récupère le message client (CHAR) et le converti en INT.
    while(bclrcv != client_id){ //Boucle pour recevoir les blocs.
    recv(csock, bufferRecv, 1024, 0); //Réception du premier bloc de 1024 caractères.
    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 connectés 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 précis :
    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 même temps

    Et si tu veux encore améliorer tu peux ajouter un multithread pour gérer plusieurs conversations en même 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 récup.
    Par défaut 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 débloqué une première 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 données sur la socket.
    Il va bloqué sur recv, recevoir une partie du message, le stocker ailleurs, de préférence dans un fichier dans ton cas, (eventuellement vider le buffer pour éviter les problèmes) 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 reçoit plus de données

    au niveau du client tu dois te connecter au serveur, et envoyer des données en boucle de la même façon, en quittant ta boucle quand ton fichier a été entièrement parcouru

    Ca te permet d'améliorer ton programme (au niveau de la performence et de ta capacité à l'améliorer plus tard), en contournant les problèmes posés 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 déja la connexion de façon unique grâce aux noms des machines et au port utilisé)



    EDIT : au fait n'oublie pas qu'en c une chaine est sensée se terminer par le caractère '\0' qui n'est pas affiché avec ta chaîne mais qui utilisera un caractère dans ton tableau
    Dernière 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 caractère, 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'espère que tu fais cela pour t'entraîner en C, car sinon je ne vois pas l'intérêt de faire cela en C, j'aurais choisi plutôt python, ou autres langages de scripts...

      Commentaire


      • #4
        Bonjour Olivier et merci de ta réponse,

        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 précis :
        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 expérience dans ce domaine est très limitée.
        Le serveur est programmé pour ne communiquer qu'avec un client, tout est déjà fonctionnel sur la connexion, l'attente d'une connexion, l'attente d'un message, l'envoi etc...

        J'ai déjà 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 forcément besoin ? Les fonctions qui reçoivent 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 série de messages.

        Il est tout de même vrai que ce n'est pas un chat à part entière, puisque que le serveur ne peut rien faire tant qu'il n'a pas reçu une réponse du client. Mais c'est justement le but recherché, je souhaite que tout soit "contrôlé" 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 récup.
        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 données sur la socket.
        Il va bloqué sur recv, recevoir une partie du message, le stocker ailleurs, de préférence dans un fichier dans ton cas, (eventuellement vider le buffer pour éviter les problèmes) 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 reçoit plus de données

        au niveau du client tu dois te connecter au serveur, et envoyer des données en boucle de la même façon, en quittant ta boucle quand ton fichier a été entièrement 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 caractère, 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'espère que tu fais cela pour t'entraîner en C, car sinon je ne vois pas l'intérêt de faire cela en C, j'aurais choisi plutôt python, ou autres langages de scripts...
          En effet, petite erreur, je corrige.
          Oui je fais ça pour m'entraîner, 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'exécution de ton code ? Grâce à 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'exécution de ton code ? Grâce à 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.
              Dernière 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'exécution de ta fonction
                }
                while (//la lecture du fichier n'est pas terminée) {
                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 récupérer les infos envoyées 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 affectée? et quand tu envoie le nombre de block je te conseille d'utilise sizeof(int) au lieu de 10 et pareil dans la réception de ton message
                idem pour envoyer les chaines déclare un buffer de 1024 et envoie sizeof(buffer)
                Dernière 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'arithmétique 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 résolu le problème, notamment grâce au code de Fred. Je l'ai légèrement "bidouillé" pour l'adapter au programme.
                    La partie aussi qui comptait les caractères et le nombre de blocs avait aussi un petit problème, il est maintenant réglé.

                    Mais, il est vrai que :

                    Code:
                    send(sock, text_log+plus, 1024, 0);
                    plus += 1024;
                    N'est surement pas la plus propre des méthodes. J'ai utilisé cette pseudo technique après l'avoir vue sur un code trouvé sur un forum.
                    Malheureusement, je ne comprends toujours pas pourquoi je recevais pourtant le code dans son entièreté... Mystère.

                    Bref, le casse-tête étant réglé je vous remercie de m'avoir conseillé, olivier & fred !

                    Bonne journée à vous,

                    Commentaire


                    • #11
                      Bonjour,

                      Content d'avoir aidé, n'hésites pas à utiliser le bouton Thanks (en bas à gauche de chaque topic) quand un topic t'as aidé particulièrement...

                      Bonne journée

                      Commentaire


                      • #12
                        J'en ai oublié les bonnes manières... Les remerciements ont été donné.

                        Dommage par contre qu'il n'y a pas une fonction résolu.

                        Commentaire


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

                          Commentaire

                          Chargement...
                          X