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

 C++ Discussion :

Envoyer une Image a travers une socket, par paquet


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2011
    Messages : 56
    Points : 39
    Points
    39
    Par défaut Envoyer une Image a travers une socket, par paquet
    Bonjour à tous.

    Jusqu'ici j'ai eu beaucoup de mal a comprendre les exemples que j'ai pu trouvé et c'est pour cela que je sollicite votre aide .

    Alors voila, j'ai développé deux programmes, côté serveur et côté client.
    Je les exécutes tous les deux sur deux machines distinctes.
    J'arrive sans difficultés à envoyer des chaines des caractères dans les deux sens avec un affichage du message en guise d'accusé de réception.
    Maintenant j'aimerais passer à la vitesse supérieur, en envoyant cette fois-ci une image.
    J'ai essayé en lisant le contenu d'un fichier .jpg et en l'envoyant par socket, après la réception j'ai balancé le contenu de ma variable dans un fichier .jpg créé automatiquement par mon programme.
    Ensuite, en cliquant dessus Windows me dit que le fichier n'est pas un bitmap valide .

    J'ai donc fais des recherches sur la toile, j'y ai trouvé des forums expliquant qu'il fallait lire et écrire respectivement avec les fonctions fread() fwrite().
    et qu'il fallait même couper l'image en plusieurs "blocs" lorsqu'il était trop lourd.

    Et c'est mon cas, mon image fait pas moins de 17Mo.
    Auriez-vous un exemple, générant tout ça ? lecture en binaire,division en plusieurs blocs, envoi, réception binaire, écriture ?

    Je demande peut-être beaucoup d'un coup, mais il doit bien avoir une âme charitable sachant programmer et qui ne demande qu'à aider un pauvre étudiant en informatique qui patine depuis deux jours sur le même problème ^^ .

    Merci d'avance,
    Cordialement,
    GibsonSG_76

  2. #2
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Salut,

    qu'il fallait lire et écrire respectivement avec les fonctions fread() fwrite().
    Peu importe la fonction..

    lecture en binaire
    tu ouvres ton fichier en binaire. Voir "man open" ou fopen.

    division en plusieurs blocs
    Alors pour ça, je te conseille d'envoyer d'abord la taille du fichier (regarde avec man fstat), puis d'envoyer la taille des blocs. C'est simplement deux entiers. Par exemple si tu choisis 10000 octets, et bien tu alloues un buffer de char de 10000. Et tu lis 10k par 10k.

    Bon il y a quand même un truc à faire attention, c'est que les fonctions read et write renvois le nombre d'octet effectivement envoyé. Donc du côté du read, tu dois faire une boucle qui appelle read tant que le bloc reçu ne fait pas 10k ou que la somme des blocs reçu ne font pas la taille du fichier. Et inversement pour le write. En bref, write et read n'envoie/reçoit pas toujours la totalité de ce que tu leur demandes d'envoyer./recevoir

    réception binaire, écriture
    Tu ouvres un fichier en mode binaire en écriture et tu écris tes blocs dedans.

    Bien entendu tu dois faire ça en utilisant TCP, soit SOCKET_STREAM.

    Après il existe mmap pour optimiser la lecture du fichier mais bon, c'est pas nécessaire pour le moment.

    Mais use et abuse des man <fonction> pour connaitre tout les détails d'une fonction, c'est souvent d'une grande aide.

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2011
    Messages : 56
    Points : 39
    Points
    39
    Par défaut Re
    Merci pour votre réponse, j'ai suivis vos conseil et j'ai effectué ceci côté client,
    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
     
    #include <iostream>
    #include <winsock2.h>
    #include <stdio.h>
    #include <iostream>
    #include <fstream>
     
    using namespace std;
    int main()
    {
        WSADATA WSAData;
        WSAStartup(MAKEWORD(2,0), &WSAData); // Fonction preparant le systeme à la generation d'une socket
     
        SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); // Déclaration et création de la socket, retourne INVALID_SOCKET si erreur.
        if( sock != INVALID_SOCKET ) // SI la socket a bien été générée, ALORS
        {
            SOCKADDR_IN sin;
            sin.sin_addr.s_addr    = inet_addr("192.168.5.245"); // IP = l'adresse IP de l'hôte sur lequel on veut se connecter ( LE SERVEUR )
            sin.sin_family    = AF_INET; // AF_INET précise que l'on va utiliser une communication de type TCP/IP, c'est-à-dire que l'on va créer une connexion à partir des adresses IP des différentes machines
            sin.sin_port    = htons(24); // Le port pouvant être choisi arbitrairement mais devant être identique à celui choisi côté serveur
     
            int error = connect(sock, (SOCKADDR *)&sin, sizeof sin);
            if(error != SOCKET_ERROR){
                cout << "Connexion effectuee" << endl;
     
                ifstream fichier("C:/Users/Pierre/Desktop/test.bmp");
                if(fichier)
                {
                    fichier.seekg(0, ios::end);
                    unsigned long int taille= fichier.tellg();
     
                    cout << "taille du fichier ouvert : " << taille << endl;
     
                    char chaine[10000];
                    char info[100];
                    int sent=0;
     
                    sprintf(info, "%d", taille);
                    send(sock, info, sizeof(info), 0);
     
                    while(sent < taille)
                    {
                        int valeur=0;
                        char carac;
     
                        for(int i=0; i < 10000; i++)
                        {
                            fichier.get(carac);
                            chaine[i] = carac;
                        }
                        cout << "SENT" << endl;
                        valeur = send(sock, chaine, sizeof(chaine), 0);
                        sent+=valeur;
                    }
     
                }
                else
                    cout << "Open fail" << endl;
     
            }
            else
                cout << "Connexion echouee" << endl;
     
        }
        return 0;
    }
    et ceci coté serveur,

    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
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
     
     
     
    #include "stdafx.h"
    #include <iostream>
    #include <fstream>
    #include <string>
     
    #include <winsock2.h>
    typedef int socklen_t;
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define PORT 24
     
    using namespace std;
     
    int main(void)
    {
       WSADATA WSAData;
       int erreur = WSAStartup(MAKEWORD(2,2), &WSAData);
     
        SOCKET sock;
        SOCKADDR_IN sin;
        SOCKET csock;
        SOCKADDR_IN csin;
        socklen_t recsize = sizeof(csin);
        int sock_err;
     
        /* Si les sockets Windows fonctionnent */
        if(!erreur)
        {
            sock = socket(AF_INET, SOCK_STREAM, 0);
     
            /* Si la socket est valide */
            if(sock != INVALID_SOCKET)
            {
                printf("La socket %d est maintenant ouverte en mode TCP/IP\n", sock);
     
                /* Configuration */
                sin.sin_addr.s_addr    = htonl(INADDR_ANY);   /* Adresse IP automatique */
                sin.sin_family         = AF_INET;             /* Protocole familial (IP) */
                sin.sin_port           = htons(PORT);         /* Listage du port */
                sock_err = bind(sock, (SOCKADDR*)&sin, sizeof(sin));
     
                /* Si la socket fonctionne */
                if(sock_err != SOCKET_ERROR)
                {
                    /* Démarrage du listage (mode server) */
                    sock_err = listen(sock, 5);
                    printf("Listage du port %d...\n", PORT);
     
                    /* Si la socket fonctionne */
                    if(sock_err != SOCKET_ERROR)
                    {
                        /* Attente pendant laquelle le client se connecte */
                        printf("Patientez pendant que le client se connecte sur le port %d...\n", PORT);
     
                        csock = accept(sock, (SOCKADDR*)&csin, &recsize);
                        printf("Un client se connecte avec la socket %d de %s:%d\n", csock, inet_ntoa(csin.sin_addr), htons(csin.sin_port));
     
                       	char size[100];
    					char recep[10000];
     
    					recv(csock, size, 100, 0);
    					int taille = atoi(size);
    					int action=0;
     
    					ofstream fichier("C:/Users/Administrateur/Desktop/reception.jpg");
    					while(action < taille)
    					{
    						action += recv(csock, recep, sizeof(recep), 0);
    						fichier << recep;
     
    					}
     
    					fichier.close();
     
                        /* Il ne faut pas oublier de fermer la connexion (fermée dans les deux sens) */
                        shutdown(csock, 2);
                    }
                }
     
                /* Fermeture de la socket */
                printf("Fermeture de la socket...\n");
                closesocket(sock);
     
                printf("Fermeture du serveur terminee\n");
            }
            WSACleanup();
        }
     
        /* On attend que l'utilisateur tape sur une touche, puis on ferme */
        system("PAUSE");
     
        return 0;
    }
    Tout semble se dérouler comme il faut, mais du coté serveur, mon fichier reception.jpg est toujours de taille 0 octet, visiblement mon code n'ecrit pas dans mon fichier.. C'est bizarre vu que mon appli en me retourne pas de String d'erreur d'ouverture de fichier lors de l'execution, une solution ?

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2011
    Messages : 56
    Points : 39
    Points
    39
    Par défaut On avance!
    En écrivant ce dernier post quelque chose a attiré mon attention,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fichier.seekg(0, ios::end);
    il fallait que je place mon "curseur" au début du fichier après avoir récupéré la taille avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fichier.seekg(0, ios::beg);

    C'est déjà mieux, mon fichier créé coté serveur se rempli, et est un peu plus lourd que l'original ( de 400 Ko ) mais le fichier coté serveur ne veut pas s'ouvrir avec toujours le même message d'erreur "Ce fichier n'est pas un fichier bitmap valide, ou son format n'est pas pris en charge"
    Une idée ?

  5. #5
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Bonjour,

    Tout d'abord c'est du C++ que tu fais, ce n'est donc pas ici la bonne catégorie. Je ne vais pas tergiverser sur le fait que le code n'est pas propre et en venir directement au problème:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for(int i=0; i < 10000; i++)
    {
      fichier.get(carac);
      chaine[i] = carac;
    }
    Et si le dernier bloc du fichier ne fait pas exactement 10000 caractères ? (D'où tes 400ko supplémentaires qui font que le fichier est invalide).


    Il faut donc corriger les endroits où tu fais des choses comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    valeur = send(sock, chaine, sizeof(chaine), 0);
    Le dernier paquet ne fera probablement pas sizeof(chaine).

    De plus je t'avais dit :
    il y a quand même un truc à faire attention, c'est que les fonctions read et write renvois le nombre d'octet effectivement envoyé.
    Ce que tu ne fais pas. Dans le code précédent, si valeur n'est pas égale à sizeof(chaine), tu iras tout de même lire la suite du fichier et ainsi écraser les octets qui n'ont pas été envoyés.

    Afin que le protocole soit un peu plus souple, envois quand même la taille d'un bloc après la taille du fichier.

    Normalement après ça, ça devra marcher

Discussions similaires

  1. Différence entre une image simple et une image 3D
    Par katebe dans le forum Traitement d'images
    Réponses: 9
    Dernier message: 29/08/2008, 18h03
  2. Réponses: 7
    Dernier message: 07/07/2008, 11h18
  3. Réponses: 4
    Dernier message: 19/06/2008, 15h41
  4. position dans une image (selection dans une image)
    Par kaiseresis dans le forum Images
    Réponses: 3
    Dernier message: 31/05/2008, 13h30
  5. Convertir une image jpeg en une image .ico. .
    Par sonja dans le forum Imagerie
    Réponses: 5
    Dernier message: 14/05/2007, 18h41

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