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 :

tutoriel Initiation à la prog. réseau sous Windows


Sujet :

Réseau C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 34
    Par défaut tutoriel Initiation à la prog. réseau sous Windows
    Bonjour a tous

    J'aurais besoin de quelques explications quant au code client.c orienté connexion de ce tutoriel voici le lien http://melem.developpez.com/tutoriel...ndows/winsock/.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    memset(&server.sin_zero, '\0', sizeof(server.sin_zero));
    je ne comprends pas cette fonction, pouvez-vous me l'expliquer et détailler ce que veulent dire les 3 arguments enfin le 3ieme évalu la taille de 'server.sin_zero' si je ne me trompe pas.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    connect(s, (SOCKADDR *)&server, sizeof(server))
    pour cette ligne de commande que se passe-t-il au niveau du second argument.Quelle valeur renvoie la fonction connect lorsque celle-ci s'est bien déroulée.

    enfin
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    send(s, "Au revoir\n", (int)strlen("Au revoir\n"), 0);
    Pourquoi il y a-t-il (int) avant le strlen.

    merci

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Par défaut
    Question 1:
    la fonction memset() sert a initialiser une zone de mémoire.
    • Le 1er paramètre est le début de la zone à initialiser
    • Le 2eme paramètre est la valeur d'initialisation
    • Le 3eme paramètre est la longueur de la zone à initialiser

    Effectivement, sizeof(server.sin_zero) retourne la taille en octets du membre de structure server.sin_zero.
    Dans ce cas précis, l'initialisation ne sert à rien, c'est juste plus "propre".

    Question 2:
    La fonction connect() attend comme 2eme paramètre l'adresse d'une structure SOCKADDR. Dans le code, la structure utilisée pour la variable "server" est une structure SOCKADDR_IN qui est presque pareille qu'une structure SOCKADDR mais pas tout à fait. Le cast "(SOCKADDR *)" sert à transformer un pointeur de structure SOCKADDR_IN en un pointeur de structure SOCKADDR parce que sinon, le compilateur, il râle et il ne veut pas compiler.

    Attention, quand on fait un cast comme cela, il faut savoir ce que l'on fait.

    Pour la valeur de retour de la fonction connect(), je te laisse regarder l'aide de cette fonction

    Question 3:
    la fonction strlen() retourne la longueur de la chaine sous la forme d'un size_t (il doit s'agir d'un nombre non signé). La fonction send() attend comme longueur un int. Comme un int, ce n'est pas tout à fait pareil qu'un size_t, il faut caster le retour pour faire plaisir au compilateur.

    Le lien de la fonction send() montre que le 2eme paramètre est aussi un size_t et donc normallement, il n'y a pas de problème. Ceci dit, sur certaine (vieilles) versions, ce paramètre peut aussi être décrit comme un int. Personnellement, je pense que size_t a plus de sens car un int, c'est signé et cela n'a pas de sens d'envoyer une longueur négative.

    Conseil : il faut apprendre le réflexe d'utiliser et à lire les pages du manuel.
    • Sur une machine : man connect
    • Sur : man connect
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 485
    Par défaut
    Bonsoir,

    Citation Envoyé par vivitron Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    memset(&server.sin_zero, '\0', sizeof(server.sin_zero));
    je ne comprends pas cette fonction, pouvez-vous me l'expliquer et détailler ce que veulent dire les 3 arguments enfin le 3ieme évalu la taille de 'server.sin_zero' si je ne me trompe pas.
    memset() sert à remplir les octets d'une portion de mémoire avec une valeur donnée. Les arguments à passer sont, respectivement, l'adresse du début de la zone, la valeur de remplissage et la taille de la zone à remplir.

    Ici, on cherche à mettre à zéro tout le champ sin_zero. L'opérateur préfixe « & » (différent du « & » logique bit à bit) sert à déterminer l'adresse en mémoire de quelque chose. Le '\0' sert à passer le caractère de valeur 00. Étant donné que le prototype de la fonction utilise int, je n'en vois pas bien l'intérêt, mais cela n'a pas beaucoup d'importance. Le sizeof sert enfin, comme tu l'as deviné, à donner la taille de la structure que l'on souhaite effacer.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    connect(s, (SOCKADDR *)&server, sizeof(server))
    pour cette ligne de commande que se passe-t-il au niveau du second argument.Quelle valeur renvoie la fonction connect lorsque celle-ci s'est bien déroulée.
    connect() va ouvrir une connexion vers l'adresse indiquée par le deuxième paramètre. Plus précisément, on passe à connect() un pointeur vers une structure de type SOCKADDR qui la contient. D'où le « & », à nouveau, pour donner l'adresse de la structure existante.

    Le transtypage (ou cast) est là parce que l'architecture des sockets, très ancienne, utilise un système d'extension de classe que l'on retrouve dans les langages orientés objets tels que le C++ ou Java, mais qui n'est pas pris nativement en charge par le C : selon le protocole utilisé, ton adresse peut être une SOCKADDR_IN (pour Internet et le protocole IP) SOCKADDR_UN, ou autres. Toutes ces familles sont construites de la même façon que la classe générique SOCKADDR et possède des membres communs, ce qui fait que la fonction peut les lire dans tous les cas. Malgré cela, le compilateur ne peut pas le savoir et considérera qu'il s'agit de types différents, engendrant donc une erreur (ou au moins un avertissement).

    Ceci t'oblige donc à faire un cast explicite de la structure utilisée vers la structure générique. Et par conséquent, la fonction ne pouvant savoir à l'avance quel genre de structure tu lui as transmise, il faut également que tu lui précise sa taille pour qu'elle puisse la gérer à la main.

    enfin
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    send(s, "Au revoir\n", (int)strlen("Au revoir\n"), 0);
    Pourquoi il y a-t-il (int) avant le strlen.
    Ça, ça ne devrait pas être nécessaire effectivement. Peut-être un prototype spécifique aux sockets Windows.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 34
    Par défaut
    Bonjour

    tout d'abord merci à ram-0000 et Obsidian pour vos post, ils m'on permis d'y voir un peu plus claire.

    Question 1:

    Obsidian a écrit au sujet de son explication sur memset() :

    Le '\0' sert à passer le caractère de valeur 00.
    Je ne comprends pas cette explication. je m'explique :

    d'apres la bibliothèque winsock2.h nous avons :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    struct sockaddr_in {
        short    sin_family;
        u_short    sin_port;
        struct    in_addr sin_addr;
        char    sin_zero[8];
    };
    je note que le champ sin_zero est de type char donc voyant qu'en 2ieme argument de la fonction memset nous avons '\0' et que ce symbole désigne le caractere de fin de chaine, je suppose que c'est celui-ci qui est placé dans sin_zero.
    Suis-je dans le vrai ? Je pense que non puisque Obsidian me dit que le champs en question est mit à zero.
    A moins que le caractere de fin de chaine '\0' signifie : met la valeur zéro dans la zone mémoire en question.

    D'autre part, si sin_zero vaut 8 octets ( [8] dans le code) je suppose que le sizeof du 3ieme argument de memset() retournera la valeur 8.

    Question 2:

    ram-0000 à ecrit :

    Le cast "(SOCKADDR *)" sert à transformer un pointeur de structure SOCKADDR_IN en un pointeur de structure SOCKADDR
    Je ne comprends pas bien cette explication :
    Pour moi ce qui se passe c'est que les données contenu dans SOCKADDR_IN sont copier/coller dans SOCKADDR, or ram-0000 nous parle de pointeur de structure , est-ce le * dans le cast "(SOCKADDR *)" ? Et ou est déclaré ce pointeur ?


    Question 3:

    ram-0000 à ecrit :

    la fonction strlen() retourne la longueur de la chaine sous la forme d'un size_t (il doit s'agir d'un nombre non signé). La fonction send() attend comme longueur un int. Comme un int, ce n'est pas tout à fait pareil qu'un size_t, il faut caster le retour pour faire plaisir au compilateur.
    Si j'ai bien compris, nous utilison la fonction strlen() pour compter le nombre de caractere du "Au revoir\n" or comme dit ci-dessus strlen() renvoie un size_t au niveau du 3ieme arguments or la fonction send() attends un int c'est pourquoi nous plassons (int) devant le strlen pour convertir la valeur size_t en int. Suis-je dans le vrai ?

    ram-0000 à ecrit :

    Le lien de la fonction send() montre que le 2eme paramètre est aussi un size_t
    Je ne comprends pas, le lien en question parle de const void *msg.

  5. #5
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Question 1 :
    '\0' est un int dont la valeur est égale à 0. Cette écriture est surtout utilisée pour souligner que cette valeur est utilisée comme un caractère de fin de chaine et la deuxième si on veut utiliser cette valeur comme valeur numérique. Mais il n'y a pas d'obligation. Il est équivalent d'écrire 0 ou '\0' : même valeur, même type.
    je note que le champ sin_zero est de type char
    Non , il est du type tableau de 8 char.
    sizeof server.sin_zero vaudra donc 8*sizeof(char) == 8.
    memset(&server.sin_zero, '\0', sizeof(server.sin_zero)) met donc tous les éléments du tableau server.sin_zero à 0.

    Question 2 :
    Et ou est déclaré ce pointeur ?
    Il n'y a pas ici d'objet pointeur : La confusion vient d'un 'abus' simplificateur de langage : &server n'est pas un objet pointeur mais une constante (de type) pointeur, c'est à dire une adresse (de la même façon si on écrit 1 , on a une constante (de type) int, une valeur, mais pas un objet int). C'est pourquoi, il est préférable à mon avis de réserver le mot 'pointeur' aux objets stockant les adresses (les constantes pointeurs). Ne pas confondre les constantes pointeur (ou adresses) avec les pointeurs constants.
    Pour éviter cette confusion, ram-0000 aurait dû écrire
    Le cast "(SOCKADDR *)" sert à transformer une adresse de structure SOCKADDR_IN en une adresse de structure SOCKADDR
    Un cast ne change jamais le type d'un objet (qui est fixé une fois pour toutes à sa création), mais le type d'une valeur.

    Question 3 :
    Suis-je dans le vrai ?
    Oui, mais comme l'a souligné Obsidian, le cast est inutile dans ce cas, la conversion sera de toute façon faite implicitement par le compilateur.

    ram-0000 à ecrit :
    Le lien de la fonction send() montre que le 2eme paramètre est aussi un size_t
    Il voulait parler du troisième paramètre. Apparemment, selon l'implémentation ce paramètre est int ou size_t (cf send())

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 34
    Par défaut
    Merci diogene la Question 1 est RESOLU je peut meme apporter une modification à la fonction memset(), le symbole & n'est pas necessaire car le prototype de la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void * memset ( void * ptr, int value, size_t num );
    nous indique enfin de se que je comprends que l'adresse de la variable du premiere argument sera utilisé automatiquement par un pointeur en arriere plan de notre fonction memeset() ( ça se fait automatiquement). Je l'ai testé et ca fonctionne.

    Question 3 RESOLU

    effectivement, le (int) en amont de la fonction strlen n'est pas necessaire car la valeur retournée par strlen() ne peut être que positive ce qui correspond bien à un size_t qui équivaut à un unsigned int.

    En revanche la Question 2 me pause toujours probleme. J'ai bien compris que les infos (adresse ip, numero de port...) que nous avons paramétré dans la structure SOCKADDR_IN serons, je ne sais comment dans le details, exportées vers la structure SOCKADDR mais ce qui me gene c'est pourquoi :

    1°/ avons nous une etoile apres la struct SOCKADDR
    2°/ SOCKADDR et l'étoile sont entre parenthèse

    d'autre part, le &server veut-il bien dire que c'est a cette adresse qu'il faut aller chercher les info a intégrer dans la structure SOCKADDR.

  7. #7
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Question 1 :
    je peut meme apporter une modification à la fonction memset(), le symbole & n'est pas necessaire car le prototype de la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void * memset ( void * ptr, int value, size_t num );
    nous indique enfin de se que je comprends que l'adresse de la variable du premiere argument sera utilisé automatiquement par un pointeur en arriere plan de notre fonction memeset() ( ça se fait automatiquement). Je l'ai testé et ca fonctionne.
    Attention, cela fonctionne pour une raison qui n'est pas du tout celle que tu crois.
    Le prototype n'indique pas que l'adresse de la variable sera utilisée automatiquement, mais que l'adresse de la variable doit être fournie.
    Dans le cas présent, effectivement le & n'a pas à figurer mais c'est uniquement parce que server.sin_zero est un tableau et donc server.sin_zero représente bien dans ce contexte l'adresse de départ du tableau. Si server.sin_zero avait été autre chose qu'un tableau, le & aurait été nécessaire.

    Question 3 :
    effectivement, le (int) en amont de la fonction strlen n'est pas necessaire ...
    Là encore, la raison n'est pas celle que tu penses.
    En fait, dans certains cas, le compilateur sait faire tout seul le transtypage en fonction du type de la valeur et du type qu'on veut obtenir. C'est le cas entre type entiers ou entre une adresse d'un type quelconque et une adresse de type void*, mais pas dans le cas de deux adresse de type quelconque (d'où le cast explicite "(SOCKADDR *)" de la question 2.

    Question 2 :
    c'est pourquoi :
    1°/ avons nous une etoile apres la struct SOCKADDR
    SOCKADDR * est la manière dont le C exprime "type adresse d'un SOCKADDR"
    2°/ SOCKADDR et l'étoile sont entre parenthèse
    Il s'agit de l'opérateur de cast (transtypage).
    (type)val signifie transformer la valeur val de son type d'origine en le type type.
    Pour moi ce qui se passe c'est que les données contenu dans SOCKADDR_IN sont copier/coller dans SOCKADDR,
    J'ai bien compris que les infos (adresse ip, numero de port...) que nous avons paramétré dans la structure SOCKADDR_IN serons, je ne sais comment dans le details, exportées vers la structure SOCKADDR
    Non, il n'y a pas de copie faite par un cast.
    Simplement on fait croire ici au compilateur que l'adresse de la structure passée en argument est celle d'une SOCKADDR. En général, il faut être prudent lorsqu'on écrit ce genre de choses car on peut arriver à des catastrophes. Dans le cas présent , Obsidian a expliqué pourquoi on peut se le permettre :
    Toutes ces familles sont construites de la même façon que la classe générique SOCKADDR ....

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Initiation à la programmation réseau sous Windows
    Par Melem dans le forum Articles
    Réponses: 7
    Dernier message: 30/03/2017, 19h43
  2. Réponses: 0
    Dernier message: 19/12/2009, 00h12
  3. PostgreSQL en réseau sous Windows
    Par bartounet dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 20/08/2007, 22h03
  4. Access en réseau Sous Windows XP
    Par christian ler dans le forum Access
    Réponses: 1
    Dernier message: 28/01/2007, 12h11

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