Encore et toujours, sockets bloquantes.

Encore et toujours, sockets bloquantes. - C++ - Programmation

Marsh Posté le 05-11-2004 à 18:14:22    

Salut,
 
j'ai une petite questions sur les sockets en C++.
J'aimerais connaitre les avantages et inconvenients des deux methodes (c'est celles que je connais, y en a ptetre d'autres) pour programmer un serveur non-bloquant:
 
- un processus et un select qui gere les descripteurs prets en lecture et ecriture.
 
- un thread par descripteur et un select par thread pour faire des send et receive non bloquants.
 
En fait je n'ai jamais utilisé la deuxieme methode sur laquelle je souhaiterais avoir plus de détails sur la manière de l'implémenter.
 
Je me pose la question, par exemple, de comment le serveur réagit s'il doit envoyer une quantité tres importante de données à un client: comment celà se passe pour les autres clients connectés et comment celà se passe pour le client en question s'il tente de renvoyer des données au serveur.
 
Merci bien pour vos réponses.

Reply

Marsh Posté le 05-11-2004 à 18:14:22   

Reply

Marsh Posté le 06-11-2004 à 00:22:29    

Déjà, ta question n'est pas C++, mais C. C'est même une question indépendante du langage, mais bon, passons, ce n'est pas bien grave.
 
Disons que si tu as plusieurs threads, tu vas consommer plus de ressources CPU. D'un autre côté, en monothread, les E/S étant synchrones par défaut, si une de tes sockets est lente, tout est ralenti (attention, ne confond pas bloquantes et synchrones, ce n'est pas la même chose).
 
L'implémentation en threads est très simple, tu n'as qu'à regarder ce post pour te donner une idée:
http://forum.hardware.fr/hardwaref [...] 9401-1.htm
 
C'est intuitivement la façon qui présente le rapport simplicité/efficacité le plus intéressant si tu as quelques sockets (moins de 20) à gérer, et que tu ne souhaites pas que l'aspect communication ne ralentisse ton programme principal.
 
Au délà d'une vingtaine de connexions en même temps, ça devient des problématiques systèmes de montée en charge. Et tu te heurtes d'un côté à l'implémentation des threads (en 1:1 ou M:N, avec ou sans lwp, etc). Et de l'autre, à l'utilisation de trucs plus sophistiqués que select(), comme epoll() ou kqueue(), ou des appels système encore plus vicieux.
 
Comme il est tard et que je vais faire dodo, je te renvoie à ça:
http://www.acme.com/software/thttpd/notes.html#nbio
 
et ça:
http://bulk.fefe.de/scalability/

Reply

Marsh Posté le 06-11-2004 à 08:56:44    

+1 pour les threads s'il n'y en a pas de trop ...

Reply

Marsh Posté le 06-11-2004 à 13:57:45    

Tiens, ça marchait pas hier, aujourd'hui ça le fait:
http://bulk.fefe.de/scalable-networking.pdf
 
C'est plutôt pas mal. Ca explique l'utilisation de sendfile() aussi.

Reply

Marsh Posté le 06-11-2004 à 19:42:00    

Superbe vraiment :) ton message m'est vraiment utile.
et puis la pages avec les différents bench.... vraiment bien.
 
Juste un truc que je comprend pas c'est quand tu parles de I/O synchrones, ça veut dire quoi ? D'autres part, comment font des serveurs comme thttpd ou zeus pour ne pas souffrir de ce ralentissement...

Reply

Marsh Posté le 06-11-2004 à 20:07:28    

Bah tout est dit, vraiment. Les outils qui montent bien en charge restent très près du système, donc avec un mix de solutions: des threads pools, des appels systèmes, et de l'asynchrone.  
 
Les threads pools (ou même des process pools à base de fork, mais je déteste fork) permettent de ne pas se casser la tête: si une thread est bloquée, alors le kernel le sait et la mettra de côté jusqu'à ce que sa condition de réveil apparaisse. Linux 2.6 est très bon là dessus par exemple.
 
Il y a ceci-dit beaucoup à dire sur la montée en charge des threads. Il est intéressant par exemple de voir comment Sun fait évoluer ses implémentation de threads java sous Solaris pour laisser tout le boulot de gestion des threads au processeur plutôt que d'utiliser du M:N:
http://java.sun.com/docs/hotspot/threads/threads.html et http://java.sun.com/j2se/1.5.0/doc [...] ities.html
 
Les appels système à mmap/epoll/kqueue/select/sendfile permettent d'éviter de passer son temps à copier les fichiers du driver disk vers la zone mémoire du client, puis vers la zone mémoire du driver reseau. Sur ce point là, le plus rapide ça reste quand même de rester tout entier dans le kernel. C'est ce que fait Tux, et il explose pas mal de benchmarks: http://www.redhat.com/docs/manuals/tux/
 
 
Et puis, une IO synchrone, c'est un truc qui te garantit que ton message est au moins envoyé (donc qui va patiemment attendre que le CPU soit dispo pour traiter ton truc, que la pile TCP/IP puisse le prendre en compte, et que madama la carte réseau soit de bonne humeur pour l'envoyer).  
 
En asynchrone, tu dis juste au kernel : tiens, prends ça dans ta face, et un jour, envoie le. Et préviens moi lorsque tu l'as fait. Tu n'attends donc pas un de ces précieux passage en mode kernel, et tu ralentis donc moins ton programme.
 
Enfin, un truc pas encore mentionné mais qui devient important au bout de quelques temps, ce sont les context-switches. Ils peuvent devenir très couteux. Pour plus d'infos, tu peux regarder SEDA:
  http://www.eecs.harvard.edu/~mdw/proj/seda/
 
Et puis ce monsieur:
  http://slashdot.org/comments.pl?si [...] id=4632094

Reply

Sujets relatifs:

Leave a Replay

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