Oui j'ai vu en effet que je mettais trompé de "noms bizarre", voir mon editEnvoyé par Médinoc
![]()
Oui j'ai vu en effet que je mettais trompé de "noms bizarre", voir mon editEnvoyé par Médinoc
![]()
Pour le cast, ça dépend: En matière de génie logiciel, il faut comparer ce qui est comparable, et un descripteur de fichier et un socket ne le sont pas sous Windows (bien qu'ils le soient sous unixoïde) : si tu fais un write au lieu de send() sur un socket, ça marchera sous linux et échouera sous Windows.
Donc, je serais d'avis de stocker directement "fd" en SOCKET dans la structure, car de toute manière, on n'est pas supposé pouvoir utiliser les deux pour la même chose.
Enfin, bien sûr, si tu ne peux pas, pour une raison quelquonque, déclarer fd en SOCKET, tu peux toujours faire un cast![]()
Pourquoi tu compares socket à un int ? Il faut le comparer à un SOCKET ou à une constante comme INVALID_SOCKET. Rien d'autre.Envoyé par sorry60
Oui, et je suis d'accord avec ce qui a été fait par Windows sur les sockets. Je l'ai repris dans mon projet 'psock' (Portable SOCKets) que j'espère publier bientôt.Envoyé par Médinoc
En fait c'etait un oubli, dans ma structure client, j'ai son nom, son mot de passe, et sa socket (que j'avais laissé en int). Donc j'ai changé son type en SOCKET et maintenant plus de problemeEnvoyé par Emmanuel Delahaye
![]()
Non c'est pas moi qui mérite le fouet ! C'est celui qui a décidé que sous windows les sockets seront des SOCKET alors que sous linux c'est des entiers !![]()
J'ai rectifié mon code (aussi bien dans l'algo que dans le codage).
Des choses fonctionnent, d'autres non![]()
Voici la boucle infini, car je pense que le reste du code est bon.
Je lance le serveur, il se positionne en ecoute sur le port :
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 FD_SET(s_ecoute,&fds_lecture); /* On ajoute la socket d'ecoute dans la liste */ ajouter_client(&unClient,"","",s_ecoute); while(1) { if ( select(max+1,&fds_lecture,NULL,NULL,NULL) != -1 ) { /* On parcourt la liste des clients */ while( unClient ) { printf("while unClient\n"); /* Si il sait passer quelque chose dans l'emsemble de lecture avec ce client */ if ( FD_ISSET(unClient->fd,&fds_lecture)) { /* Si c'est la socket d'ecoute ==> nouvelle connexion ! */ if ( unClient->fd == s_ecoute ) { unsigned int size_client_addr = sizeof(client_addr); SOCKET newClient = accept(s_ecoute,(struct sockaddr *)&client_addr,&size_client_addr); int oct_rec; if ( newClient != INVALID_SOCKET ) { char login[16]; printf("Connexion d'un nouveau client : %s...\n",inet_ntoa(client_addr.sin_addr)); if ( newClient > max ) { max = newClient; } /* On attend la réception de son login */ oct_rec = recv(newClient,login,sizeof(login),0); if ( oct_rec != - 1) { /* On procède à l'authentification du login */ int authent = authentification(login); if ( authent == 0 ) { /* Authentification reussie ! */ /* On met le nouveau client dans la liste */ ajouter_client(&unClient,login,"",newClient); /* On le met aussi dans l'ensemble de lecture */ FD_SET(newClient,&fds_lecture); } else { /* Client inconnu ! */ char erreur404[] = "Desole vous n'etes pas dans la base de donnees...\n"; int oct_env; /* On envoie un message d'erreur au client inconnu */ oct_env = send(newClient,erreur404,sizeof(erreur404),0); if ( oct_env == -1 ) { perror("send() 404error"); } } } else { perror("revc() login"); } } else { perror("accept()"); } } else { /* Le client en cours a fait une action ! */ int oct_rec; char message[144]; /* 16 premiers octets pour le login du destinataire, le reste c'est le message */ oct_rec = recv(unClient->fd,message,sizeof(message),0); if ( oct_rec <= 0 ) { /* Erreur ou deconnexion client */ printf("Deconnexion de %s...\n",unClient->login); /* On le retire de l'ensemble de lecture */ FD_CLR(unClient->fd,&fds_lecture); /* On le retire de la liste */ retirer_client(&unClient,unClient->fd); } else { /* Le client a envoye un message ! */ printf("%s a envoyé %d octets !\n",unClient->login,oct_rec); } } } unClient = unClient->suivant; } /* Fin du parcour de la liste */ } else { perror("select()"); } } /* Fin de la boucle infinie */
Je lance un client, et me connecte au serveur, c'est bon :Attente de connexion sur le port 4000...
J'envois un message au serveur contenant mon login, c'est bon aussi :Connexion d'un nouveau client : 127.0.0.1...
Je lance un deuxieme client, ça donne la meme chose, donc c'est deja pas mal de ce coté là.Toma vient de se connecter...
Maintenant ce qui cloche : quand j'envoie un deuxieme message au serveur avec un client, lene se fait pas.
Code : Sélectionner tout - Visualiser dans une fenêtre à part printf("%s a envoyé %d octets !\n",unClient->login,oct_rec)
Je ne trouve pas d'où vient le probleme, j'espere que vous saurez m'aider.
Merci
Hum... Peut-être que l'événement n'est pas vu...
Tu pourrais mettre un printf juste après le if(FD_ISSET) ?
PS: Pour une discussion sur Windows et les sockets, tu peux jeter un coup d'oeil au thread [Socket] Client UDP...
Je pense avoir une idée de l'origine du probleme.Envoyé par Médinoc
Je vais essayer d'expliquer clairement mon idée...![]()
La boucle infinie commence, le FD_ISSET se fait sur le 1er element de la liste (s_ecoute), elle capte donc le connect et peut mettre le newclient dans le liste et dans l'ensemble de lecture.
Mais le hic, c'est que ma fonction qui ajoute un élément dans la liste, le rajoute en début de liste, donc il ne sera jamais évalué par FD_ISSET![]()
Comme il est rajouté au debut de la liste, quand le programme arrive à
cela donne NULL, donc ça quitte la boucle et je pense que plus jamais on ne rentre dedans car à aucun moment je fais revenir le pointeur de liste sur le premier élément de la liste
Code : Sélectionner tout - Visualiser dans une fenêtre à part unClient = unClient->suivant![]()
Voila à mon avis cela vient au moins d'ici.
Peut etre que je me trompe, en tout cas je vais essayer de corriger ça.
Ah, j'ai trouvé une origine du bug!
Il faut reconstituer entièrement le fd_set avant CHAQUE appel de select(). (c'est plus que jamais valable sous Unixoïde, mais je ne sais pas si ça a vraiment une influence sous Windows. Quoi qu'il en soit, il FAUT le faire de toute façon).
Bref, il te faut un pointeur sur le début de la liste chaînée (un pointeur que tu ne modifieras pas, sauf si tu fais des insertions/suppressions au début), et dans la boucle, juste avant le select(), tu fais un FD_ZERO puis tu parcoures à ta liste pour remplir le fd_set avec FD_SET. Après le select, tu la parcoures à nouveau pour tester chaque client avec FD_ISSET.
Pourquoi faire un FD_ZERO juste avant le select ? FD_ZERO remet à 0 tout l'ensemble de lecture (fds_lecture chez moi). Donc si je le remet à 0, il ne contiendra plus les "anciens clients"Envoyé par Médinoc
![]()
Pour l'histoire du pointeur au debut de la liste, ça je suis ok (voir ma reply précédente).
Merci pour ton aide![]()
Le FD_ZERO, on le fait:
1° Parce que ça fait table rase, et que c'est plus propre: On devrait toujours faire un FD_ZERO avant de remplir la liste.
2° Si un client vient de se déconnecter, il apparaitra encore dans la liste avant d'y être retiré.
Et si tu as bien compris ce que je t'ai dit, il faut FORCÉMENT re-remplir le fd_set avant le select (car sous unixoïde et sans doute aussi sous Windows, il n'y restera plus que les clients qui avaient envoyé des données). Donc, puisque de toute façon la liste doit être reconstruite, on la remet à zéro et on la reconstruit à partir de rien.
Ok et le fd_set, je le re-remplit en utilisant ma liste chainée, c'est bien ça ?Envoyé par Médinoc
oui.
Voila j'ai fait les modifs mais malheureusement ça ne change rien du tout![]()
Je les post car c'est pas un possible que j'ai mal 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
19
20
21
22
23
24
25
26 /* ... */ /* Pointeur sur le debut de la liste */ struct client* deb_liste; /* On met la socket d'ecoute dans l'ensemble de lecture */ FD_SET(s_ecoute,&fds_lecture); /* On ajoute la socket d'ecoute dans la liste */ ajouter_client(&unClient,"","",s_ecoute); deb_liste = unClient; while(1) { /* on reconstitue le fds_lecture */ FD_ZERO(&fds_lecture); unClient = deb_liste; while ( unClient ) { FD_SET(unClient->fd,&fds_lecture); unClient = unClient->suivant; } if ( select(max+1,&fds_lecture,NULL,NULL,NULL) != -1 ) { /* On se repositionne en debut de liste et on la parcourt */ unClient = deb_liste; while( unClient ) { /* ...*/
ben oui, ça devrait être ça. Tu vas pouvoir reprendre le débogage en mettant des printf, par exemple, juste avant et après le select(), et aussi juste après le if(FD_ISSET) ... à chaque étape, quoi...
Oui justement j'ai mis un printf juste apres apres le FD_SET qui m'indique sur quel login le FD_SET a agit :Envoyé par Médinoc
Et ce qui m'etonne c'est qu'il m'affiche à chaque fois le login vide, c'est à dire celui que j'ai donné à ma socket d'ecoute...
Code : Sélectionner tout - Visualiser dans une fenêtre à part printf("FD_ISSET sur %s\n",unClient->login);
hum... Demande-lui aussi d'afficher la valeur des pointeurs unClient et unClient->login...
Et si tu pouvais poster cette partie-là du code...
Qu'entends tu par "valeur des pointeur" ?Envoyé par Médinoc
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