Récupérer l'état d'une socket en sortie d'un select()

Récupérer l'état d'une socket en sortie d'un select() - C++ - Programmation

Marsh Posté le 12-11-2005 à 11:02:10    

Bonjour,
 
Je suis amené à gérer les connexions de plusieurs clients sur un serveur, en effectuant un select() sur ma socket serveur et l'ensemble des sockets déjà créées pour les clients.
J'aimerais savoir comment tester l'état des sockets sélectionnées par le select(), car cette fonction rend la main dès qu'une socket envoie des données ou se ferme côté client, sans que je sache pour l'instant distinguer les cas.
 
Merdi d'avance :jap:
 
NB : je développe sous linux, pas de fonctions windows, donc ;)

Message cité 1 fois
Message édité par v10ware le 12-11-2005 à 12:50:30
Reply

Marsh Posté le 12-11-2005 à 11:02:10   

Reply

Marsh Posté le 12-11-2005 à 11:21:39    

v10ware a écrit :

Je suis amené à gérer les connexions de plusieurs clients sur un serveur, en effectuant un select() sur ma socket serveur et l'ensemble des sockets déjà créées pour les clients.
J'aimerais savoir comment tester l'état des sockets sélectionnées par le select(), car cette fonction rend la main dès qu'une socket envoie des données ou se ferme côté client, sans que je sache pour l'instant distinguer les cas.


Suffit de lire la doc de select()... Montre ton code...


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 12-11-2005 à 11:34:17    

Je passe tout simplement au select un fd_set avec les descripteurs de sockets dont je veux savoir si je peux y lire quelquechose.
 
Quand le client envoie des données, on quitte le select(), on lit les données et basta. Quand le client se déconnecte, on quitte également le select() comme si il y avait des données à lire sur la socket... J'aimerais savoir comment connaître l'état de la socket pour ne pas essayer de lire des données sur quelquechose de fermé.
 
Bon, mon code est en C++, mais j'ai choisi de le placer en C parceque c'est essentiellement un problème de fonctions C...
socketModify est une classe de manipulation de fd_set, Socket est une classe contenant le socket descriptor, les clés des maps sont les socket descriptors aussi...
 

Code :
  1. void SocketPool::select(map<int, Socket*> *mapSocket)
  2. {
  3.     if (mapSocket== NULL)
  4.     {
  5.         throw Exception(-1);
  6.     }
  7.     // construction du fd_set a passer au select()
  8.     socketModify.reset();
  9.     for (map<int, Socket*>::iterator it = pool.begin(); it != pool.end(); it++)
  10.     {
  11.         socketModify.add(it->first);
  12.     }
  13.     socketModify.add(ss.getDescriptor());
  14.     // select : le fd_set est modifie
  15.     int nbSockArrived = ::select(FD_SETSIZE, socketModify.getFd_Set(), NULL, NULL, NULL);
  16.    
  17.     if (nbSockArrived == -1)
  18.     {
  19.         // erreur du select
  20.         throw Exception(errno);
  21.     }
  22.    
  23.     if (nbSockArrived > 0)
  24.     {
  25.         for (map<int, Socket*>::iterator it = pool.begin(); it != pool.end(); it++)
  26.         {
  27.             // ajout des sockets actives a la liste
  28.             // il faudrait tester ici si la socket est active parcequ'elle a ete fermee par le client
  29.             // si c'etait le cas, il faudrait remplir une deuxieme liste indiquant a l'appelant
  30.             // quelles sont les sockets fermees
  31.             if (socketModify.isset(it->first))
  32.             {
  33.                 (*listSocket)[it->first] = it->second;
  34.             }
  35.         }
  36.         if (socketModify.isset(ss.getDescriptor()))
  37.         {
  38.             // la socket serveur a recu une nouvelle connexion
  39.             Socket *connec = new Socket(ss.accept());
  40.             pool[connec->getDescriptor()] = connec;
  41.         }
  42.     }
  43. }

Reply

Marsh Posté le 12-11-2005 à 12:52:15    

Voila... Même si je continue à croire que c'est un problème de fonctions qui ne regardent que le C, donc je voulais mieux cibler... Bref, on va pas épiloguer. Une idée ?

Reply

Marsh Posté le 12-11-2005 à 12:54:16    

RTFM
 
$ man select
 


---------------
Nos estans firs di nosse pitite patreye...
Reply

Marsh Posté le 12-11-2005 à 13:02:54    

Tiens, j'y avais pas pensé :|
 
Tu veux bien le lire toi-même et me dire à quel endroit est indiquée la possibilité de savoir quel est l'état exact d'une socket en sortie du select ?


Message édité par v10ware le 12-11-2005 à 13:03:13
Reply

Marsh Posté le 12-11-2005 à 13:05:01    

a tout hasard, le code de retour ?


---------------
Nos estans firs di nosse pitite patreye...
Reply

Marsh Posté le 12-11-2005 à 13:12:47    

moi je préfère poll/epoll :)
 
sinon man select_tut

Reply

Marsh Posté le 12-11-2005 à 13:23:47    

v10ware a écrit :

Voila... Même si je continue à croire que c'est un problème de fonctions qui ne regardent que le C


Non. C'est un problème d'utilisation d'une fonction système. C'est indépendant du langage.


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 12-11-2005 à 13:30:51    

KangOl a écrit :

a tout hasard, le code de retour ?


-1 : erreur
>= 0 : nombre de descripteurs selectionnés, qui figurent dans les fd_set modifiés par le select().
Pas d'information sur l'état des descripteurs, donc :/
 

Taz a écrit :

moi je préfère poll/epoll :)
 
sinon man select_tut


 
j'avais fait une recherche, j'ai trouvé un topic où tu parles de poll/epoll, je me suis un peu renseigné, il semble que ce soit quelquechose d'assez récent dont je ne sais pas si c'est disponible sur le système de développement de mon école (je suis sur un linux récent chez moi, mais là bas c'est un FreeBSD pas très frais...). Je regarderai quand même. Et je regarderai aussi select_tut :jap:
 

Emmanuel Delahaye a écrit :

Non. C'est un problème d'utilisation d'une fonction système. C'est indépendant du langage.


ok :jap:
 
 
Mais sinon, je pensais qu'il devait peut-être exister un appel système dont je n'aurais pas connaissance et qui permettrait de récupérer l'état d'un descripteur... Si vous avez des renseignements là dessus :)

Reply

Marsh Posté le 12-11-2005 à 13:30:51   

Reply

Marsh Posté le 12-11-2005 à 13:40:13    

v10ware a écrit :

Mais sinon, je pensais qu'il devait peut-être exister un appel système dont je n'aurais pas connaissance et qui permettrait de récupérer l'état d'un descripteur... Si vous avez des renseignements là dessus :)


 
FD_CLR / FD_ZERO / FD_SET permet de positionner le bit correspondant au socket à surveiller (en général on a un socket serveur, FILENO_STDIN et et c'est tout...). Ensuite, FD_ISSET permet de déterminer qui a bougé.
 
http://www.linux-france.org/articl [...] ect-2.html
 
Rappel :  
2 = fonction système
3 = fonction C...


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 12-11-2005 à 13:48:40    

Je pense avoir bien saisi le fonctionnement des fd_set et les macros associées, donc j'arrive à les construire et les lire. Simplement, après lecture du fd_set retourné par select(), je ne sais pas déterminer la raison pour laquelle select() a retenu un descripteur particulier dans le fd_set retourné.
 
Comme j'ai dit, que la socket cliente ait envoyé des données ou qu'elle se soit déconnectée, elle figure dans le fd_set readfds, et là je ne sais pas comment me comporter.
 
Alors dans le cas où il s'agit d'arrivée de données, je sais qu'il faut que je lance un read() (ou peut etre un recv(), je viens de me souvenir de cette fonction peut être plus adaptée au cas des sockets), mais il serait bien que je ne tente pas de lire des données sur une socket fermée (après test ca me renvoie indéfiniment le même caractère ascii étendu 0xbf, et je ne pense pas que ce soit un critère suffisant pour déclarer la socket comment étant fermée, sauf si vous me confirmez le contraire).
 
sinon, merci pour le rappel sur la classification des pages man, j'ai jamais su exactement à quoi correspondaient les catégories :jap:

Reply

Marsh Posté le 12-11-2005 à 14:41:44    

select craint en terme de montée en charge et personnellement je ne trouve pas son API et ses fd_set pratiques. poll est mieux, plus performant et plus simple à utiliser à mon avis. Quant à epoll c'est vraiment génial, avec une sémantique beaucoup plus riche.

Reply

Marsh Posté le 12-11-2005 à 19:44:47    

Je viens de passer à poll, qui a le mérite d'indiquer la raison pour laquelle une socket est sélectionnée. Mais ce que je ne saisis pas bien, c'est que quand le client ferme sa socket, poll() détecte une activité sur la socket associée côté serveur (jusque là, comme select()) mais en indiquant que la raison est qu'il y a des données à lire (le champ "revents" contient POLLIN) et non que la socket est fermée (POLLHUP).
 
J'étais tout confiant et paf, l'enthousiasme retombe :/
Je vais quand même garder poll et virer select sur les conseils de Taz, mais ça ne résoud pas mon problème :/

Reply

Marsh Posté le 12-11-2005 à 20:19:37    

bah t'as un POLLIN, et quand tu tentes un recv, là tu constates que EOF

Reply

Marsh Posté le 12-11-2005 à 20:46:27    

Ce serait donc le caractère -65 que je reçois, EOF ?
Mais dans ce cas, à quoi correspond POLLHUP ?
 
Arf, en cherchant pendant que je rédige ma réponse, je tombe là dessus : http://www.greenend.org.uk/rjk/2001/06/poll.html
Il faudrait qu'ils se mettent d'accord :D


Message édité par v10ware le 12-11-2005 à 20:46:39
Reply

Marsh Posté le 12-11-2005 à 21:03:54    

EOF c'est EOF

Reply

Marsh Posté le 12-11-2005 à 22:13:04    

Bon, après plusieurs tests, il semblerait que ce ne soit pas EOF qui soit lu sur la socket, mais NUL. Je ne sais pas si c'est correct, mais ça marche ;)
 
Merci à tous, et merci pour poll :jap:

Reply

Marsh Posté le 12-11-2005 à 22:31:50    

NUL ? regarde le retour de recv, si c'est 0, c'est EOF. man recv

Reply

Marsh Posté le 12-11-2005 à 23:05:58    

Le retour de recv est bien 0, donc je lisais dans un buffer rempli de caractères NUL puisqu'initiliasé juste avant la lecture.
 
A ce sujet, les pages de man des serveurs de mon école ne mentionnent pas ce que signifie la valeur de retour 0 pour recv... Mais chez moi il est effectivement dit que cela signifie que la connexion est terminée.
 
Merci bien pour ton expertise, je vais pouvoir faire du code à peu près propre ;)

Reply

Marsh Posté le 13-11-2005 à 00:12:44    

n'hésite pas à consulter la VO du man
 
LC_ALL=C man poll
 
par exemple. Beaucoup de tradutions sont bugguées.

Reply

Marsh Posté le 13-11-2005 à 00:50:20    

Ce sont bien les pages anglaises que je consultais, mais le contenu dépend certainement des systèmes et/ou des versions des pages de man.
 
D'ailleurs, concernant recv, le man des serveurs de l'école n'indique rien concernant la valeur de retour 0, mais j'espère que la fonction se comporte de la même façon que chez moi...

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed