Tu pourrais poster ton code source actuel? (Avec les affichages de valeurs)
Tu pourrais poster ton code source actuel? (Avec les affichages de valeurs)
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 ; }
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:
(là, courant sera NULL ou non, et s'il est NULL, pas de problème avec le while())
Code : Sélectionner tout - Visualiser dans une fenêtre à part const struct listeClients * courant = l->suivant ;
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:
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 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); }
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)
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); } }
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 :
affichage du pseudo avant le message du 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
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 printf("%s :", formatChaine(courant->nom)) ;
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 ?
Oui c'est justement comme ca qu'il faut faire.Envoyé par innosang
Les clients etant bloqué sur le select lorsque le serveur leur parle ils lisent sur leur socket, le message envoyé par le serveur.
Tu peux eventuellement ne pas envoyer le message au client qui a parlé.
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
Je ne me rappelle plus si tu l'a dis mais ton chat est pour Windows, Linux ou les 2?
Petite erreur dans le code il te faut 2 indices, un i et un jEnvoyé par innosang
Je ne comprend pas pourquoi tu veux supprimer les \n.
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 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.
/!\ 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)
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); }
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.
(Attention, c'est écrit à la va-vite et non testé, mais c'est l'idée générale)
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 } }
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)(Attention, il me semble bien que là, on perd la compatibilité Windows: je n'ai pas testé)
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.aspEnvoyé par Dark_Ebola
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...
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager