j'ai commencé un serveur de tchat en C, et évidement, comme bcp de débutants (j'éspère ^^) j'ai un problème avec select...
j'arrives pas a l'utiliser malgré ce qui était écrit dans le linux mag 41...
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#define MYPORT 1789
#define NOMBREMAX 20
typedef struct{
char pseudo[20];
} client;
int envoi(int a, int b, char *chaine){
int retour;
retour=send(a, chaine, strlen(chaine), b);
if (retour == -1){
perror("send");
close(a);
}
return retour;
}
main(){
char msg[4097];
int len;
int sockfd, nombre=0, i, j, k;
client tchateur[NOMBREMAX];
struct sockaddr_in my_addr, their_addr;
int sin_size;
int new_fd[NOMBREMAX];
struct timeval tv;
int retval;
fd_set rfds;
tv.tv_sec=0;
tv.tv_usec=200;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
perror("socket");
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero), 8);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1){
perror("bind");
exit(1);
}
while (1)
{
//recherche un nouveau pour se connecter
if ( listen(sockfd, NOMBREMAX)== -1){
perror("listen");
exit(1);
}
sin_size = sizeof(struct sockaddr_in);
if ((new_fd[nombre] = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1){
perror("accept");
printf("ERREUR...\n");
}
printf("nouveau connecté : %s\n", inet_ntoa(their_addr.sin_addr));
envoi(new_fd[nombre], 0, "\n\n\t\tBienvenu sur le serveur de Max\nListe des commandes :\n\tEXIT pour quitter.\n\tLISTE PSEUDO pour avoir la liste des personnes connectés\nPseudo : ");
len = read(new_fd[nombre], tchateur[nombre].pseudo, 19);
tchateur[nombre].pseudo[19]=0;
//finit le pseudo car si il est plus grand que 20 caractères alors il aurait été tronqué...
nombre++; //un connecté de plus
for (i=0; i<nombre-1; i++) //préviens tt le monde sauf le nouveau
{
envoi(new_fd[i], 0, "Connexion de :");
envoi(new_fd[i], 0, tchateur[nombre-1].pseudo);
}
//fin de le recherche de nouveau connecté
for (j=0; j<4097; j++){
msg[j]=0;
}
len = read(new_fd[i], msg, 4096);
if ( msg[0]==69 && msg[1]==88 && msg[2]==73 && msg[3]==84 && msg[3]==84 )
{ //Si la comende "EXIT" est tapée alors on déconnecte le client et on refraihit la liste
close(tchateur[i].new_fd);
printf("déconnexion de : %s", tchateur[i].pseudo);
for (j=0;j<nombre;j++){ //préviens tt le monde que machin s'est déconnecté
if (j!=i){ //i est déconnecté
envoi(new_fd[j], 0, "déconnexion de : ");
envoi(new_fd[j], 0, tchateur[i].pseudo);
}
}
for (j=i; j<nombre-1; j++){ //refraichit la liste
new_fd[j]=new_fd[j+1];
for (k=0;k<20;k++){
tchateur[j].pseudo[k]=tchateur[j+1].pseudo[k];
}
}
nombre--;
}
else if(msg[0]==76 && msg[1]==73 && msg[2]==83 && msg[3]==84 && msg[4]==69)
{ //Si "LISTE" est tapée alors
for (j=0;j<nombre;j++){ //on affiche tt les pseudos
envoi(new_fd[i], 0, tchateur[j].pseudo);
}
}else{
for ( j=0; j < nombre; j++) //envoi à tt le monde ce que i dit
{
if (j != i){ //mais ne l'envoi pas a i
envoi(new_fd[j], 0, tchateur[i].pseudo);
envoi(new_fd[j], 0, "\t");
envoi(new_fd[j], 0, msg);
}
}
}
}
}
je sais déja que même si la j'arrives a faire qqch, le serveur de bloqueras à chaque nouvelle connecion, si la personne ne mets pas de pseudo, mais c'ets un détail de dèrnière minute, la, je cherches a faire fonctionner select... et je n'ai aps mis select ici, car je ne sais même pas comment faire pour l'utiliser mis a part l'ini des variables et encore pas toutes loin de la, juste leur déclaration...
# Select
Posté par JaguarWan . Évalué à 2.
[^] # Re: Select
Posté par JaguarWan . Évalué à 2.
--- FDZERO(&fdLecture); FDZERO(&fdEcriture); FDZERO(&fdException);
+++ FDZERO(&fdSetEcouteur);
Et toutes les macros FD** demandent l'adresse du set, même si j'ai oublié quelques '&' au passage...
[^] # Re: Select
Posté par bidulemax . Évalué à 1.
ça devrait m'être très utile.
[^] # Re: Select
Posté par bidulemax . Évalué à 1.
j'ai testé, mais ça marche toujours pas... je n'arrives pas a me connecter au serveur...
[^] # Re: Select
Posté par gc (site web personnel) . Évalué à 2.
Pourquoi ?
# utorial sur les socket et 'select' en particulier
Posté par Nicolas LAURENT . Évalué à 2.
http://perso.club-internet.fr/nicolas-laurent/C/socket-13.html(...)
Dans ton code, c'est le accept() qui est bloquant. La bonne solution est bien d'utiliser select().
Bon courage.
[^] # Re: utorial sur les socket et 'select' en particulier
Posté par bidulemax . Évalué à 1.
Donc, maintenant mon problème est : il ne sort jamais de select, même si je me connecte au serveur...
Donc, voila, même si je n'ai pas de messages d'erreurs à la complation, je suis toujours coincé ^^...
merci pour ton tuto, je le lis la, et il a l'air plutot complète et bien expliqué bravo !
[^] # Re: utorial sur les socket et 'select' en particulier
Posté par JaguarWan . Évalué à 2.
Si tu as utilisé mon code succint, c'est normal : c'est l'algo d'un mini serveur qui ne fait qu'écouter et signaler s'il y a des données sur les sockets. Déplace donc ton code de gestion de connexion dans le if(FD_ISSET(....)) pour plus de résultats.
Sinon, tu auras du mal à faire un serveur gérant plusieurs connexions sans faire appels aux threads, pour éviter la gène des opérations bloquantes et pouvoir traiter simultanément différents clients.
Autre option, utiliser des i/o non bloquantes sur tes sockets, mais ça utilise plus de CPU.
[^] # Re: utorial sur les socket et 'select' en particulier
Posté par bidulemax . Évalué à 1.
[^] # Re: utorial sur les socket et 'select' en particulier
Posté par gc (site web personnel) . Évalué à 3.
Le problème c'est que ça complexifie beaucoup le programme (mutex), je ne suis pas sûr que ça vaille le coup pour un serveur qui calcule rapidement la réponse (i.e. sans appel à une base de données ni à d'autres ressources réseaux distantes).
# J'AI TROUVE
Posté par bidulemax . Évalué à 1.
http://coucou747.hopto.org(...)
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.