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 :

utilisation de select() pour faire un Tchat


Sujet :

Réseau C

  1. #21
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    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 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Tu pourrais poster ton code source actuel? (Avec les affichages de valeurs)

  2. #22
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    189
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 189
    Points : 60
    Points
    60
    Par défaut
    voilà j'arrive à faire en sorte que plusieurs clients se connectent ...

    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
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    include "fonc_socket.h"
     
     
    int main(char * argv[], int argc)
    {
    	int s_ecoute = createBindInetSocket(SOCK_STREAM,1234) ;
    	char c ;
    	struct sockaddr_in client;
    	struct hostent * h ;
     
    	int i ;
    	int lg = sizeof(struct sockaddr_in) ;
     
    	struct listeClients * l =listeNouv();
     
    	if (listen(s_ecoute,10)<0)
    	{
    		perror("erreur listen") ;
    		return(-2) ;
     
    	}
    	else
    	{	printf("listen réussi \n") ;
    		//printf("Serveur lancé ! En attente de messages ...\n") ;
     
     
    		fd_set fdread ;
    		int ret ;
     
     
    		while(1)
    		{
     
    			int fd ;
    			FD_ZERO (&fdread) ; // on met à zero l'ensemble fd_set	
    			FD_SET(s_ecoute, &fdread) ; // on ajoute la socket d'ecoute à lensemble fd_set
    			const struct listeClients * courant = l ;
     
    			while(courant!=NULL) // on ajoute les descripteurs des fichiers ouverts à l'ensemble fd_set
    			{
    				FD_SET(courant->s,&fdread) ;
    				//printf("%d\n", courant->s);
    				courant=courant->suivant ;
    			}
     
     
    			if ((ret=select(FD_SETSIZE,&fdread,NULL,NULL,NULL))==-1)
    			{
    				perror("erreur select") ;
    				exit(-2) ;
     
    			}
    			else
    			{
     
     
    				courant=l ;
    				while(courant!=NULL)
    				{
    					if(FD_ISSET(courant->s, &fdread)) // un client tappe quelque chose au clavier
    					{
     
     
     
     
    							printf("%s :", formatChaine(courant->nom)) ;
    								while(read(courant->s, &c, 1)>0 && c!='\0')
       								putchar(c);
     
     
     
     
     
    					}
    					courant=courant->suivant ;
     
    				}
     
    				if(FD_ISSET(s_ecoute, &fdread)) /* on ecoute sur la socket d'ecoute pour voir si un nouveau client se connecte*/
    				{
     
     
    					if ((fd=accept(s_ecoute, (struct sockaddr *)&client,&lg))==-1)
    					{
    						perror("erreur accept") ;
    						return(-1) ;
     
    					}	
    					else
    					{	
    						char nom[50] ;
    						read(fd,nom,50) ; // on lit le pseudo du nouveau client 
    						//printf("desc %d \n", fd) ;
    						//printf("ajout d'un nouveau client\n") ;
    						l = ajoutListe(l,fd,nom) ;
     
     
     
    					}
    				}
     
     
    			}
    		}
     
     
    	}
     
     
     
     
     
     
     
     
     
    	close(s_ecoute) ;
    	return 0 ;
    }

  3. #23
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    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 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Bon, OK.
    Premièrement, j'ai vu pourquoi tu as un socket "zéro" au départ: c'est parce que ta liste chaînée, même vide, contient un élément.

    Comme on sait que cet élément n'est pas supposé être NULL, (tu peux rajouter un test juste derrière le "struct listeClients * l =listeNouv();"), tu peux démarrer la recherche à l'élément suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const struct listeClients * courant = l->suivant ;
    (là, courant sera NULL ou non, et s'il est NULL, pas de problème avec le while())


    Maintenant, on va s'assurer de retirer un client quand la lecture c'est mal passée.
    Pour cela, il nous faudra modifier ce qui ce passe là-dedans:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
                   if(FD_ISSET(courant->s, &fdread)) // un client tappe quelque chose au clavier
                   {
     
                         printf("%s :", formatChaine(courant->nom)) ;
                            while(read(courant->s, &c, 1)>0 && c!='\0')
                               putchar(c);
     
                   }
    Il nous faut un contrôle plus précis du résultat:
    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
     
    if(FD_ISSET(courant->s, &fdread))
    {
    	int resRead;
    	printf("%s :", formatChaine(courant->nom));
    	while((resRead=read(courant->s, &c, 1))>0 && c!='\0')
    		putchar('c');
     
    	//On retire le client si la lecture a échoué ou s'il n'y a plus rien a lire
    	if(resRead <= 0)
    	{
    		printf("%s s'est deconecte.\n", formatChaine(courant->nom));
    		close(courant->s);
    		//Retire le client de la liste chaînée:
    		//Il faudra que tu fasses le nécessaire dans cette fonction
    		retirer_de_liste(l, courant);
    	}
    }
    Une fois que ça marchera, on pourra rajouter le relais des messages vers les autres clients (dès qu'un client enverra un message, tous les autres le recevront)

  4. #24
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    189
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 189
    Points : 60
    Points
    60
    Par défaut
    la deconnexion d'un client fonctionne ...

    pour le moment j'essaie de faire en sorte que le pseudo du client s'affiche sur le seveur avant ce qu'il a tappé ... comme sur un vrai tchat

    pseudo : bonjour tout le monde

    celà fonctionne à peu près sauf que j'ai des caractères bizarres après le pseudo et je me casse la tete à essayer de trouver ce que c'est.

    lecteur du pseudo chez le client et envoit vers le serveur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	char * nom = (char *) malloc(50 *sizeof (char)) ;
     
    	printf("Veuillez entre un pseudo :\n") ;
    	scanf("%s", nom) ;
    ....
    send(s,nom, strlen(nom),0)	; // envois du pseudo

    lecture du pseudo envoyé par le client :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    						char * nom = (char *) malloc(50 * sizeof(char));
    						read(fd,nom,50) ; // on lit le pseudo du nouveau client
    affichage du pseudo avant le message du client:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("%s :", formatChaine(courant->nom)) ;
    sachant que ma fonction formatChaine est censé supprimé les caractères en trop mais elle ne le fait pas:
    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
     
    char * formatChaine(char * ch)
    {
    	char rep[49] ;
    	int i ;
     
    	for(i=0 ; i<strlen(ch) ; i++)
    	{
    		if (ch[i]!='\n')
    		rep[i]=ch[i] ;
     
    	}
     
    	rep[i]='\0' ;
     
    	return rep ;
     
    }

    ah oui autre question ... pour transmettre les messages reçu par le serveur vers les autres clients ... est ce que le serveur peut ecrire dans les socket(ceux de la liste) pour que les clients puissent lire dedans ?

  5. #25
    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
    Citation Envoyé par innosang
    ah oui autre question ... pour transmettre les messages reçu par le serveur vers les autres clients ... est ce que le serveur peut ecrire dans les socket(ceux de la liste) pour que les clients puissent lire dedans ?
    Oui c'est justement comme ca qu'il faut faire.
    Les clients etant bloqué sur le select lorsque le serveur leur parle ils lisent sur leur socket, le message envoyé par le serveur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Pour tous les clients de la liste 
    Faire
        Ecrire le message sur la socket
    Fin pour
    Tu peux eventuellement ne pas envoyer le message au client qui a parlé.
    Je ne me rappelle plus si tu l'a dis mais ton chat est pour Windows, Linux ou les 2?

  6. #26
    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
    Citation Envoyé par innosang
    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
     
    char * formatChaine(char * ch)
    {
    	char rep[49] ;
    	int i ;
     
    	for(i=0 ; i<strlen(ch) ; i++)
    	{
    		if (ch[i]!='\n')
    		rep[i]=ch[i] ;
     
    	}
     
    	rep[i]='\0' ;
     
    	return rep ;
     
    }
    Petite erreur dans le code il te faut 2 indices, un i et un j
    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
     
    char * formatChaine(char * ch)
    {
    	char rep[49] ;
    	int i,j;
     
    	for(i=0,j=0 ; i<strlen(ch) ; i++)
    	{
    		if (ch[i]!='\n')
    		    rep[j++]=ch[i] ;
    	}
     
    	rep[j]='\0' ;
     
    	return rep ;
    Je ne comprend pas pourquoi tu veux supprimer les \n.
    Je vois pas comment il peut y en avoir dedans.
    Si le type il tape son pseudo et fais entrée, il n'y a pas \n dedans.

  7. #27
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    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 382
    Points : 41 588
    Points
    41 588
    Par défaut
    /!\ Attention, là, tu retournes l'adresse d'une variable locale automatique... Ici, mieux vaut modifier la chaîne passée en paramètre (remplaçant tout caractère compris entre 1 et 31 par un caractère bouche-trous (un point par exemple) et le \n par un \0)

    De plus, remplace ton scanf() par un fgets() (là, il y aura effectivement un \n à la fin, sauf si le pseudo est plus grand que le buffer: il sera tronqué avant le \n)

  8. #28
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    189
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 189
    Points : 60
    Points
    60
    Par défaut
    lorsqu'un client tape quelque chose au clavier le serveur les receptionne ... et les envois à tous les autres clients. par contre le client n'arrive pas à receptionne les messages venant du serveur. j'ai crée un fils qui s'occupe de la reception des messages venant du serveur ai-je bien fait ?
    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
     
    	int f = fork() ;
     
    if (f==0)
    	{
    		while(read(s,&c,1)>0) ;
    		printf("%c", &c) ;
    	}	
     
    	while(1) // le client boucle pour l'envoit de messages
    	{
     
    		char szMessage[80]; 
     		fgets(szMessage, 80, stdin); 
     		send(s, szMessage, strlen(szMessage)+1, 0);
     
     
    	}

  9. #29
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    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 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Hum. Je dirais que non, tu as mal fait: je ne sais même pas si un socket peut vraiment être partagé sous unixoïde...

    Là aussi, il faut utiliser un select(). Mais pas sur deux sockets: Sur un socket (celui qui est connecté au serveur) et l'entrée standard (descripteur 0)

    (Attention, il me semble bien que là, on perd la compatibilité Windows: je n'ai pas testé)

    Ainsi, si un message arrive pendant que tu tapes, il sera affiché (plus ou moins bien: un conseil, affiche un \n avant d'afficher le message).
    Si tu appuies sur entrée, le message est envoyé au 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
    while(1)
    	{
    	fd_set fds;
    	FD_ZERO(&fds);
    	FD_SET(s);
    	FD_SET(0);
    	if(select( bla bla bla )==-1)
    		break;
    	if(FD_ISSET(0))
    		{
    		//Lire sur l'entrée standard et Envoyer le message
    		}
    	if(FD_ISSET(s))
    		{
    		//Lire le socket et afficher
    		}
    	}
    (Attention, c'est écrit à la va-vite et non testé, mais c'est l'idée générale)

  10. #30
    Membre expérimenté
    Avatar de granquet
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    1 201
    Détails du profil
    Informations personnelles :
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 201
    Points : 1 421
    Points
    1 421
    Par défaut
    (Attention, il me semble bien que là, on perd la compatibilité Windows: je n'ai pas testé)
    effectivement, impossible de faire marcher select avec le stdin sous windows. ou alors j'ai pas trouvé ! (je me suis pris la tete une bonne semaine)

    seule astuce (plutot "crade") que j'ai trouvé, utiliser les pthread => compatibilité windows.

  11. #31
    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 : 68
    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 Dark_Ebola
    (Attention, il me semble bien que là, on perd la compatibilité Windows: je n'ai pas testé)
    effectivement, impossible de faire marcher select avec le stdin sous windows. ou alors j'ai pas trouvé ! (je me suis pris la tete une bonne semaine)

    seule astuce (plutot "crade") que j'ai trouvé, utiliser les pthread => compatibilité windows.
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/select_2.asp

    Il n'est question que des sockets. Pas du tout des fichiers en général. C'est pas étonnant, parce qu'au niveau système Win32, les fichiers sont gérés par FileOpen() etc avec un handle, et non par open() etc. qui est plutôt unixoide tendance POSIX.1... Une fois plus, POSIX.1 est mal supporté par Windows...

    Philo UNIX != philo Windows... C'est pas nouveau... Peut être que dans 10 ans, Windows sera full POSIX.1... Après tout, on assiste bien à la fois aux convergences Mac/unix et Mac/Intel...

Discussions similaires

  1. Utiliser UPDATE + SELECT pour faire un cache FIFO
    Par WeeJay dans le forum Langage SQL
    Réponses: 5
    Dernier message: 19/05/2008, 13h10
  2. utiliser un Formulaire pour faire un état
    Par girl257 dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 19/09/2007, 20h13
  3. utilisation du TChart pour faire des graphiques
    Par tchimou dans le forum Bases de données
    Réponses: 2
    Dernier message: 30/04/2007, 15h59
  4. utiliser données texte pour faire des calculs
    Par sarah67 dans le forum Access
    Réponses: 20
    Dernier message: 06/02/2006, 15h09

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