Transmition de fichier avec les socket

Signaler
-
 Themaletron -
Bonjour.

Je cherche a créer un programme capable de transmettre un fichier par le réseaux.

Pour cela j'utilise les socket, je vous prévient je suis débutant en la matière !

Voici les sources du programme qui envoie le fichier :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <winsock2.h>
typedef int socklen_t;

#define PORT 6666
#define MAXIMUM 50
#define T_LIGNE 100

int main()
{
    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;

    int i, a;
    char  ligne[T_LIGNE] = {'\0'};
    int tailleFichier = 0;
    char PATH[MAXIMUM] = {'\0'}, extension[MAXIMUM] = {'\0'};

    FILE * fichier = NULL;

    printf("Bienvenu dans le telechageur de fichier | version ALPHA\n\n");

    printf("Chemin du fichier a envoye : ");
    scanf("%s", PATH);

    for(i 0, a 0; PATH[i] != '\0'; i++)
    {
        if(PATH[i] == '.')
        {
            while(PATH[i+1] != '\0')
            {
                i++;
                extension[a] = PATH[i];
                a++;
            }
        }
    }

    if(strcmp("rar", extension) != 0 && strcmp("zip", extension) != 0 && strcmp("exe", extension) != 0 && strcmp("txt", extension))
    {
        printf("\nL'extension choisie n'est pas accepte par le telechageur de fichier !\nVeuillez a ce qu'elle soit un .rar, un .zip, un .exe ou un .txt !\n\n");
        goto stop;
    }

    else if((fichier fopen(PATH, "rb")) NULL)
    {
            printf("\nImpossible d'ouvrir : %s\n\n", PATH);
            return EXIT_FAILURE;
    }

    fseek(fichier, 0, SEEK_END);
    tailleFichier = ftell(fichier);

    printf("\nTaille du fichier = %d octets soit %.3f ko\n  Confirmer l'envoie du fichier en entrant 1 sinon 2  =  ", tailleFichier, (float)tailleFichier/1000);
    scanf("%d", &a);

    if(a != 1)
    goto stop;

    if(!erreur)
    {
        sock = socket(AF_INET, SOCK_STREAM, 0);

        /* Si la socket est valide */
        if(sock != INVALID_SOCKET)
        {
            printf("\n\nLa 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("Recherche d'une connexion sur le port %d...\n", PORT);

                    csock = accept(sock, (SOCKADDR*)&csin, &recsize);
                    printf("Connexion entrante avec la socket %d de %s:%d\n\n", csock, inet_ntoa(csin.sin_addr), htons(csin.sin_port));

                     sock_err = send(csock, extension, 50, 0);

                    for(i = 0; i != tailleFichier; i++)
                    {
                        fgets(ligne, 100, fichier);
                        sock_err = send(csock, ligne, 100, 0);

                        if(sock_err == SOCKET_ERROR)
                        {
                            printf("Erreur de transmission\n");
                            goto stop;
                        }

                    }


                    if(sock_err != SOCKET_ERROR)
                        printf("fichier %s envoyer !\n", PATH);
                }
            }
        }
    }

    stop :

    if(fichier != NULL)
    fclose(fichier);

    shutdown(csock, 2);

    printf("Fermeture de la socket\n");
    closesocket(sock);
    printf("Fermeture du serveur terminee !\n");

    WSACleanup();
    return EXIT_SUCCESS;
}



Voici les sources du programme qui recois le fichier :
#include <stdio.h>
#include <stdlib.h>

#include <winsock2.h>
typedef int socklen_t;

#define PORT 6666

int main()
{
    WSADATA WSAData;
    int erreur = WSAStartup(MAKEWORD(2,2), &WSAData);

    SOCKET sock;
    SOCKADDR_IN sin;
    char IP[50] = {'\0'}, extention[50] = {'\0'}, PATH[50] = {'\0'};
    char ligne[100] = {'\0'}, uneFois = 0, valide = 0;

    FILE * fichier = NULL;

    printf("Bienvenu dans le telechageur recepteur | Version ALPHA\n\nChoisissez l'IP pour se connecter : ");
    scanf("%s", IP);

    /* Si les sockets Windows fonctionnent */
    if(!erreur)
    {
        /* Création de la socket */
        sock = socket(AF_INET, SOCK_STREAM, 0);

        /* Configuration de la connexion */
        sin.sin_addr.s_addr = inet_addr("127.0.0.1");
        sin.sin_family = AF_INET;
        sin.sin_port = htons(PORT);

        /* Si l'on a réussi à se connecter */
        do
        {
        if(connect(sock, (SOCKADDR*)&sin, sizeof(sin)) != SOCKET_ERROR)
        {
            valide = 1;
            printf("Connection à %s sur le port %d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));

            if(uneFois == 0 && (recv(sock, extention, 50, 0) != SOCKET_ERROR))
            {
                uneFois = 1;
                sprintf(PATH, "nouveau_fichier.%s", extention);
                fichier = fopen(PATH, "wb");
            }

            while(recv(sock, ligne, 100, 0) != SOCKET_ERROR)
            {
                printf("%d", recv(sock, ligne, 100, 0) != SOCKET_ERROR);
                    printf("Donnee recu...\n\n");
                    fprintf(fichier, "%s", ligne);
            }
        }
        /* sinon, on affiche "Impossible de se connecter" */
        else
        {
            valide = 0;
            printf("\n\nRecherche d'un hote...\n");
            Sleep(1000);
        }
        }while(valide == 0);

        /* On ferme la socket */

    }

    WSACleanup();
    fclose(fichier);

    return EXIT_SUCCESS;
}


Mon programme "serveur" marche plutôt bien, enfin je pense.
Par contre pour ce qui est du programme "client" il ne fonctionne pas tres bien !
J'ai une infinité de "Donnee recu..." ! Je ne sais pas comment faire en sorte que l'envoie de donné s’arrête une fois qu'il n'a plus rien a envoyer !

En vous remerciant d'avance...
A voir également:

5 réponses

Pas mal du tout... on dit un socket non ?
Je pense que cela ne peut pas fonctionner...
Le serveur ne devrait pas avoir a etre "configuré" puisque le protocol permet justement au serveur d'avoir confiance en plusieurs connexions et qu'il y a obligation de definir le nombre maximal de connexions au serveur. en plus, big lol, on "get" les infos de connexions qui ne sont pas imaginaires mais belles et biens dans chaque en-tete de chaque paquet plutot que de les definir, alors que les quelques fonctions des protocols TCP/IP oblige definitions des arguments qui vont entre virgules entre les parenthses, d'une certaine facon on a pas le droit d'ouvrir un socket avant d'avoir l'expression des arguments qui permettent identification des 2 Ordinateurs. donc, les sockets en vérité, on les ouvre pour mettre qqch dedans qui va alors dans le reseau ou bien pour mettre qqch, mais qui provient du reseau, en l'occurence pour un serveur, d'un client qui sera potentiellement jamais unique, même si ton programme client va avec ton prog serveur, la possibilité du serveur d'accepter des connexions vient en plus de l'ouverture d'un socket, de l'identification du bonne ordinateur et non du bon client qui aurait le bon prog. en fait la fonction connect sert dans le client et dans le serveur pour 2 raisons différentes. et c'est la fonction gethostname qui est un passage obligé pour les 2 programmes parceque, le serveur-receveur ne pourra pas "ouvrir" un socket qui recoit des informations, meme sur le port ouvert si son nom "char" n'est pas reconnu en tant qu'hostname, ensuite, le serveur se connect a son socket receptacle, et ensuite il ecoute son socket (listen(sock, int BACKLOG))
Obligé de définir un nombre max de connexion strictement supérieur à 0 si le serveur veut entendre une connexion. Bref, impossible d'etablir une connexion entre 2 adresse IP sans leurs hostnames et donc, avoir les adresses des sockets (celui du client pour que le client sache à quel socket envoyé ses datas pour qu'elles soient ensuite envoyées, ces datas ; et puis l'hostname du serveur qui devra ne pas pouvoir se faire passé pour un autre vers son socket à lui auquel il voudra se connecter lui aussi, mais pour l'ecouter, si il y a quelquechose dedans, puisqu'il faudra qu'il considère que le client est bel et bien "Host" grave à l'identification par port privé en 1 occasion, et non pas un host qui serait lui-même mais un distant. c'est qu'est effet ta connexion n'est pas sécurisée assez pour que le serveur n'accepte pas n'importe quel ordinateur, pourvu qu'il vueille envoyé le bon fichier...et...lol...
J'ai trouvé ça sur un site... justement je me renseigne sur les sockets en win32...(cf fin du message)...C'est pure théorie *<;o)
et socket.h me semble plus simple ;o)d'alleurs... "l'histoire" de "STREAM" en fin d'argument, est relative a sys/socket.h donc et est double dans Winsock2 qui ne permet l'usage du parametre SOCK_DGRAM qu'apres avoir forcément utilisé au moins 1 fois le parametre SOCK_STREAM plutot en tant qu'argument qu'en tant que parametre, avant l'usage de la fonction socket avec l'argument SOCK_DGRAM pour faire alors transiter "rapidement" l'information une fois justement que le "Streaming" est reconnu. cela evite d'avoir a se connecter au socket pour le serveur, ce qui est toujours plus pratique, si il n'a qu'à engeristrer les infos d'un socket vers un fichier. autant utiliser socket pour se pouvoir recevoir et pour envoyer les infos du socket au disque-dur, cela evite le listen inutile... ou alors, on fait du printf apres un listen si on est pas sur de recevoir le bon fichier,lol, ou pour le lancer le cheksum ou un antivirus plus tot que prévu ;o)...

accept(sock, (SOCKADDR *)&csin, &sizeof_csin) : la fonction qui va nous permettre d'accepter une connexion, une autre fonction très simple. 1er paramètre : le socket. Le 2ème paramètre est votre SOCKADDR_IN que vous avez créé pour prendre les informations du client connecté sur votre serveur. Le 3ème et dernier paramètre est un pointeur vers la variable qui va recevoir le nombre d'octets écrits dans votre SOCKADDRIN. La variable doit être initialisée avec la taille de cette structure.

http://c.developpez.com/cours/sockets-c-cpp-demystifies/
Des zéros et des (H)uns
Le "Pas mal du tout" c'était ironique ?

Je suis débutant dans le réseaux et c'est assez difficile d'avoir les bons réflexes en un seul jour !

Je sais comment fonctionne les fonctions que j'utilise, pas besoin de perdre du temps pour ça, j'attendais plutôt un code plus ou moins corriger avec des indications...

Enfin bref, j'ai pas compris ton message, tu me parles de socket.h et il n'y pas de rapport, tu parles aussi de HOSTNAME, c'est quoi le rapport ?

Tu marques beaucoup de chose pour pas grand chose au final, mais je te remercie d'avoir posté.

Enfin, c'est pas grave, j'ai pus aboutir a mon projet et mon programme est désormais opérationnel.
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
3
salut,
déja tu as deux lignes qui sont bien suspectes: fgets(ligne, 100, fichier); puis send(csock, ligne, 100, 0);
je passe le fait de faire des fgets sur des fichiers binaires genre exe ou rar, ça n'a pas vraiment de sens.
ensuite, tu envoies un bloc de 100 octet a chaque fois, independemment de la taille de la ligne. est ce que c'est bien ce que tu veux faire ?
enfin tu boucles sur tailleFichier qui a l'air de contenir la taille du fichier, et non pas son nombre de ligne (pas logique).
voila les quelques erreurs qui me sautent aux yeux en survolant tes programmes
bon courage
Messages postés
3833
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 juin 2021
122
Bonjour.

@Heureka: Je ne peux pas t'aider, ne connaissant que très mal les API windows :(

@Themaletron: Je ne comprends pas l'aggressivité de ton message. Si tu avais face à toi un "branleur" (entends par là un type de profil récurrent que l'on a sur ce site ^^, qui veut du travail tout fait), je ne dis pas. J'aurais même compris ta réaction. Mais ici, le posteur est de bonne foi. Sa question est claire, bien posée, il est poli et il poste son code. Il cherche à comprendre, et est tout à fait conscient que son code n'est pas optimal. Il ne fait ici que demander des conseils.
Il aurait été plus judicieux de ta part de ne pas te moquer de lui ("lol" à répétition dans ton message), et de lui expliquer d'une manière pédagogique l'ensemble des petites erreurs ou maladresses présentes dans son code. Il y a sur le fond de ton message des informations utiles, mais la forme est désagréable.


________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Re..Ce n'est pas moqueur... c'est seulement transparent de ma part, j'ai eu du mal a caché mon euphorie parce que je me disais que ca risquait pas de marcher pour une ligne sur 2... Je me renseignais sur l'usage des protocols TCP/IP sous windows et j'etais super content de voir que qqun avait (quand même) essayé de mettre winsock2.h dans les preprocs... ce qui est certains, c'est que pour windows, ce n'est pas comme sous linux... Les WSAPIs obligent des buffers en transitions apres les sockets, donc apres les "paquets" (datagrammes). Je ne voulais pas me moquer, je debute en coding sous windows 7 depuis 3 jours, lol. au contraire, c'est plutot des remerciements tu m'as aidé à m'y interessé plus... jete un oeil a Netmon.h, microsoft montre ce que l'on peut faire des paquets (datagrammes)... c'est fouilli, mais on comprend qu'on ne peut pas faire passer d'une machine à une autre tout un fichier sans utiliser du buffering à la reception serveur...
hier, j'ai tenté de compiler mon premier prog en C/C++ sous windows avec code::blocks et visual studio express... je sais que ce n'est le sujet, mais on dirait que le pure language C (prinf et surtout fprintf) ne se compile pas en meme temps que des objets... parce que, le header stdio.h est pour les systemes de fichier sur platform *Nix, où l'utilisateur a un droit d'ecriture dans un autre format... sous win, la gestion d'ecriture ne se fait pas comme ca, ca marche pas chez moi en tous cas, ca se debug meme pas. et puis j'ai rencontré un autre probleme... avec CAPTURE_Packets (cf netmon.h from sdk's includes - microsoft), si on a pas une carte wifi "pro" qui permet un certain type de flux, tu te renseigneras sur backtrack... notre ordi bug au moment de runner un prog de monitoring par exemple, j'ai,essayé,,hier...,pire, une fois que tu refermes ton IDE, tu lances un autre prog qui passe par les protocols TCP/IP, et la, forcément, tu as le message d'erreur quivte dis que le programme s'est fermé car il avait cessé de fonctionner. morale de l'histoire... Il y a necessité d'avoir win serveur 2008 ou win server 2008 pro et une carte WAN adaptée au TCP/IP pour que ca marche sous windows, sinon, tu ne peux meme pas "appeler" les "tools" en rapport avec la "transmission de datagrammes" de microsoft sans un gros bug qui plante la carte wifi... lol j'en suis encore sur le cul, j'ai pas trouvé mieux que de contourner le language C en trifouillant avec SQL serveur. ca semble impossible d'echanger des données en 1 temps sous windows à partir de 2 progs en C/C++... Je suis débutant aussi sous windows, plus que toi même ;o) je buche... désolé de pas trouvé de solution a ton probleme qui est le meme que le mien... je continu a chercher !
Des zéros et des (H)uns