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 :

[Socket] Client UDP


Sujet :

Réseau C

  1. #1
    Membre à l'essai
    Inscrit en
    Janvier 2005
    Messages
    12
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 12
    Points : 12
    Points
    12
    Par défaut [Socket] Client UDP
    Bonjour,

    J'ai développé un Client/serveur UDP, le serveur ne m'a pas posé de problème, par contre le client oui

    En fait il envoi bien les informations et les recoit convenablement aussi,

    il se décompose en 2 parties, la première étant la réception d'informations et la deuxieme, la saisie, mon problème vient du fait qut je ne peux pas gerer la saisie et la reception en même temps.

    quelle serai à votre avis la meilleure méthode pour palier à ce problème ?

    j'ai pensé à utiliser deux threads, la première qui s'occuperai de la reception de données et la deuxième et de la saisie et de l'envoi de données, mais n'y aurait-il rien de plus simple ?

    merci d'avance de vos réponses

  2. #2
    Expert éminent sénior
    Avatar de Skyounet
    Homme Profil pro
    Software Engineer
    Inscrit en
    Mars 2005
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 6 380
    Points : 13 380
    Points
    13 380
    Par défaut
    un select pour plus d'informations voir man select
    ou Google si tu n'a pas Linux

  3. #3
    Membre actif Avatar de sorry60
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    802
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 802
    Points : 253
    Points
    253
    Par défaut
    Citation Envoyé par Skyrunner
    un select pour plus d'informations voir man select
    ou Google si tu n'a pas Linux
    Ou Ici
    Ou encore [urlhttp://beej.us/guide/bgnet/output/html/index.html]Ici[/url] c'est le même en plus complet, mais en anglais
    Ou sinon la celebre MSDN

  4. #4
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par sorry60
    Citation Envoyé par Skyrunner
    man select
    Ou sinon la celebre MSDN
    A ma connaissance, select() ne fonctionne pas sur les IO sous Windows. Je serais content d'être contredit sur ce point...

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    select() marche parfaitement avec les sockets sous Windows, du moment qu'on utilise les fd_set et les fonctiosn appropriées. Par contre,
    1°) Le paramètre de nombre est ignoré (il est là juste pour garder un prototype compatible)
    2°) Les fonctions read() et write() sur des sockets ne marchent pas sous Windows: Il faut utiliser send() et recv(). De même, close() ne marche pas non plus, il faut utiliser closesocket() ---> Sinon, erreur "bad file descriptor".

  6. #6
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Médinoc
    select() marche parfaitement avec les sockets sous Windows,
    Oui, mais je parlais des IO, genre stdin, ou STDIN_FILENO...

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Ah, oui, alors là, ça ne doit pas marcher: sous unixoïde, select() marche sur des descripteurs, et les sockets en sont, mais sous Windows, select() marche sur les sockets, qui sont des HANDLEs...

    Par contre, il serait intéressant de tester select() sur un handle autre qu'un socket (à mon avis, select() utilise WaitForMultipleObjects()). On peut récupérer les handles des IO standards avec GetStdHandle()...

  8. #8
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Médinoc
    Ah, oui, alors là, ça ne doit pas marcher: sous unixoïde, select() marche sur des descripteurs, et les sockets en sont, mais sous Windows, select() marche sur les sockets, qui sont des HANDLEs...

    Par contre, il serait intéressant de tester select() sur un handle autre qu'un socket (à mon avis, select() utilise WaitForMultipleObjects()). On peut récupérer les handles des IO standards avec GetStdHandle()...
    OK, ça devrait effectivement fonctionner mieux comme ça. Windows, c'est ... bizarre...

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    ben, non: Ca a ce point commun avec unix que les sockets sont interprétés comme des fichiers ouverts à bas niveau...

    Simplement, à WinNT, il y a trois niveaux (handle, descripteur, FILE *) alors que sous Unixoïde, il n'y en a que deux (descripteur et FILE *).

    D'accord, il aurait sûrement été plus portable d'ouvrir directement les sockets au niveau descripteur plutôt que handle... Heureusement, ils ont laissé la possibilité de passer de l'un à l'autre avec desc=_open_osfhandle(handle), l'équivalent à bas niveau de FILE *pt_f=fdopen(desc)...

  10. #10
    Membre à l'essai
    Inscrit en
    Janvier 2005
    Messages
    12
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 12
    Points : 12
    Points
    12
    Par défaut
    tout dabord merci pour ces réponses, je fais mon client sous linux,
    j'ai regardé le man de select mais j'avoue ne pas tout saisir dans son utilisation (je suis un débutant en C )

    voici mon code pour le moment :

    ma fonction de traitement de chaines :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    char *TraitChaine(char *msg,char *psd,int *lg,int *stop)
    {
    /*fonction de traitement de chaine de caractère*/
    msg = (char*)malloc(sizeof(char)*ECHOMAX);/*allocation de la chaine à la taille max*/
    printf("%s : ",psd);
    scanf("%s",msg);
    *stop=strcmp(msg,"/quit");
    if(*stop==0)strcpy(msg,"fin de La conversation");
    *lg=strlen(msg);
    return(msg);
    }
    les daclarations de variables :
    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
     
     int sock;                        /* descripteur socket */
        struct sockaddr_in ServAddr;     /* Adresse du serveur (structure)*/
        struct sockaddr_in AddrRecept;   /* adresse source de reception des msg */
        unsigned short PortEcoute;       /* Port d'écoute */
        unsigned int TailleAddr;         /* taille d'adresse pour recvfrom() */
        char *servIP;                    /* adresse du serveur */
        char *EnvoiChaine;               /* chaine à envoyer au serveur */
        char echoBuffer[ECHOMAX+1];      /* chaine à traiter */
        int LgChaineEnvoi;      /* longueure de la chaine à envoyer */
        int LgChaineRecue;               /* longueure de la chaine recue */
        int log,ok,fin; 		     /*variable booleen indiquant si l'option de log a été activé ou pas*/
    /*ok est un boolen nous disant si les paramètres passés semblent corrects*/
    /*fin est utilisé pour la detection de demande de fin de programme*/
        char *fichier,pseudo[15];
        FILE *fic;
    et enfin le code de mon main :


    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
     
    og=0;
    fin=1;
    printf("verification des paramètres\n");
    ok = GestionParam(argc,argv,&log,fichier);
        if(ok)
    	{
    	servIP = argv[1];           /* premier argument : adresse ip du serveur */
            PortEcoute = atoi(argv[2]);  /* port spécifié en paramètres */
    	}
        else 
    	{
    	AffichErreur("Utilisation : %s <IP du serveur> [<Port d'utilisation>] <nom_fichier_log (active le log en auto)>\n");
    	exit (0);
    	}
     
        /* Creation du socket UDP */
        if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
            AffichErreur("creation de socket échouée");
     
        /* Construction de la structure d'adresse pour la communication avec le serveur*/
        memset(&ServAddr, 0, sizeof(ServAddr));    
        ServAddr.sin_family = AF_INET;                 /* famille d'adresse : Internet (les adresses locale fonctionnent aussi */
        ServAddr.sin_addr.s_addr = inet_addr(servIP);  /* Adresse IP du serveur */
        ServAddr.sin_port   = htons(PortEcoute);     /* port utilisé */
    /*preparation du log de conversation si il y a besoin*/
    if(log==1)
    {
    fichier=(char *)malloc(sizeof(char)*strlen(argv[3]));
    strcpy(fichier,argv[3]);
    printf("ouverture du fichier : %s pour log des conversations\n",fichier);
    fic=fopen(fichier,"a");
    }
     
    /*demande du pseudo de l'utilisateur*/
    printf("donner votre pseudo :");
    scanf("%s",pseudo);
    printf("connexion au serveur!\n");
    strcpy(EnvoiChaine,"test");
    LgChaineEnvoi=strlen(EnvoiChaine);
    if (sendto(sock, EnvoiChaine, LgChaineEnvoi, 0, (struct sockaddr *) &ServAddr, sizeof(ServAddr)) != LgChaineEnvoi) AffichErreur("erreur d'envoi au serveur");
    strcpy(EnvoiChaine,"");/*ré initialisation de la chaine à envoyer*/
    while(fin==1)
    	{
    	/*traitement de la chaine à envoyer*/
    	EnvoiChaine=NULL;
    	EnvoiChaine=TraitChaine(EnvoiChaine,pseudo,&LgChaineEnvoi,&fin);
        	if (sendto(sock, EnvoiChaine, LgChaineEnvoi, 0, (struct sockaddr *) &ServAddr, sizeof(ServAddr)) != LgChaineEnvoi) AffichErreur("erreur d'envoi au serveur");
     
    	    /* gestion de la réponse */
        	TailleAddr = sizeof(AddrRecept);
        	LgChaineRecue = recvfrom(sock, echoBuffer, ECHOMAX, 0,(struct sockaddr *) &AddrRecept, &TailleAddr);	
    	printf("%d",LgChaineRecue);
        	if (ServAddr.sin_addr.s_addr != AddrRecept.sin_addr.s_addr)
        	{
            AffichErreur("Reception de packet d'une source inconnue!!\n");
            exit(1);
        	}
     
     
     
     
        	/* creation manuelle de la fin de chaine de caractères */
        	echoBuffer[LgChaineRecue] = '\0';
        	printf("%s\n", echoBuffer);    /* affichage de la chaine reçue */
    	/*lancement de l'écriture dans le fichier si besoin est*/
    	if(log==1) GestionLog(fic,echoBuffer);
    	}
       if (log==1) fclose(fic);
        close(sock);/*fermeture du socket*/
        exit(0);
    }
    je sais que mon code n'est pas très propre, il qu'il mériterai à être décomposé en plus de fonctions
    Pour ce qui est de la fonction select() elle s'appuie sur un descripteur de fichier, ce descripteur est il mon descripteur de socket ?
    pour ma saisie de chaine de caractères, faut il que j'utilise une fonction non bloquante ?
    car en fait là mon problème est que le scanf étant bloquant le programme ne peux recevoir d'infos qu'après validation de la saisie et qu'une seul message.

    merci d'avance de vos réponses.

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    select() marche partout avec les descripteurs de socket.
    Et sous linux, les descripteurs de socket sont également des descripteurs de fichier.

    Pour la saisie de chaînes de caractères, tu n'as pas de fonction non-bloquante en standard. On utilisera donc select() sur ton socket et l'entrée standard pour agir dès que l'un des deux a des données en entrée.

  12. #12
    Membre à l'essai
    Inscrit en
    Janvier 2005
    Messages
    12
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 12
    Points : 12
    Points
    12
    Par défaut
    petite question,

    j'ai bien réussi à attendre les entrées de saisie clavier, mais pour attendre en même temps les données arrivante par le reseau, faut il que je créer 2 variable de type fd_set ? ou au contraire une seule et jongler avec FD_SET ?

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    une seule:
    pour CHAQUE appel de select(), tu fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    FD_ZERO(&readFds);
    FD_SET(STDIN_FILENO, &readFds);
    FD_SET(socket, &readFds);
     
    int res = select(socket+1, &readFds, NULL, NULL, NULL);

Discussions similaires

  1. Programmation socket: client UDP
    Par ThE_BuG87 dans le forum C++
    Réponses: 3
    Dernier message: 08/01/2007, 12h25
  2. cherche exemple client udp socket
    Par - Glop - dans le forum Réseau/Web
    Réponses: 5
    Dernier message: 08/06/2006, 10h52
  3. [SOCKET] Client UDP sur système Unix
    Par be_tnt dans le forum Développement
    Réponses: 1
    Dernier message: 14/04/2006, 21h31
  4. Réponses: 2
    Dernier message: 12/10/2004, 13h04
  5. [SOCKET] Client C connecté à un serveur Java
    Par missllyss dans le forum Développement
    Réponses: 2
    Dernier message: 07/06/2004, 13h14

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