OVH Cloud OVH Cloud

Pb détection cloture socket en mode non bloquant

16 réponses
Avatar
Sébastien Cottalorda
Salut à tous,

Mon système:
Mandrake 10.1 (kernel 2.6.8.1-12 - Perl 5.8.5-3)

J'utilise un programme qui se connecte, en mode non bloquant, à
plusieurs serveurs TCP.

Voici comment il marche:

#=================================================================
# Programme multi-clients
#
&ouverture_de_toutes_les_sockets_en_mode_non_bloquant();

while (1){
foreach ($select->can_read()){
# recevoir les données des sockets m'ayant envoyé
# quelque chose
}
foreach ($select->can_write()){
# envoyer les données des buffers dans les sockets
# Si problème d'envoi, alors cloturer la socket
# en question
}
foreach ($select->has_exception()){
# NOP
}
}
#==================================================================


Le problème est que à chaque fois qu'une socket meurt (coupée par
l'autre partie), impossible de la détecter.
Je considère donc qu'elle est toujours valide.

Comment puis-je détecter une cloture de socket en mode non bloquant.

Merci d'avance.

Sébastien

6 réponses

1 2
Avatar
Paul Gaborit
À (at) Tue, 26 Jul 2005 16:54:51 +0200,
Paul Gaborit écrivait (wrote):
À (at) Tue, 26 Jul 2005 14:03:26 +0000 (UTC),
Nicolas George <nicolas$ écrivait (wrote):
Je viens de survoler la doc de ce module, et au premier regard, j'ai
l'impression que l'API est assez foireuse. Et pendant que j'écrivais ce
message, j'ai regardé les sources, et ça confirme : ce module est une
connerie.


Heu... Un module écrit par Graham Barr est rarement (jamais?) une
connerie !


Ce package en particulier l'est d'autant moins qu'il est maintenant
distribué avec Perl. ;-)

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>


Avatar
Nicolas George
Paul Gaborit wrote in message :
Les méthodes distinctes sont utiles lorsqu'on n'attend que des
lectures, que des écritures ou que des exceptions.

La fonction 'select' gère le cas général et permet de récupérer
imméditatement les objets à traiter. Elle est vraiment *beaucoup* plus
simple d'usage que la fonction 'select' primitive.

En fait, ce module, bien utilisé, me semble très pratique et encapsule
les choses proprement (la manipulation des fd et des vecteurs de bits
n'est pas vraiment simples à faire). Mais, effectivement, il n'empêche
pas de faire n'importe quoi.


Je trouve que l'API est mal choisie, alors, et la documentation n'est
vraiment pas là pour améliorer les choses : rien qu'à lire le synopsis, on a
la très nette impression que can_read/can_write sont les méthodes normales
du module, et il faut attendre les détails pour entendre parler de la
méthode select, qui passe pour une fonction d'utilisation avancée, rarement
utile.

Alors que c'est le contraire : l'usage normal est select, et
can_read/can_write sont des cas particuliers moins utiles.

À mon avis, une API plus intelligente aurait été d'avoir un paramètre de
mode à la méthode add, pour indiquer si on souhaite surveiller un fd donné
en lecture, en écriture ou les deux, et une seule méthode en tout et pour
tout pour faire le test.

Avatar
Paul Gaborit
À (at) Tue, 26 Jul 2005 15:25:55 +0000 (UTC),
Nicolas George <nicolas$ écrivait (wrote):
Je trouve que l'API est mal choisie, alors, et la documentation n'est
vraiment pas là pour améliorer les choses : rien qu'à lire le synopsis, on a
la très nette impression que can_read/can_write sont les méthodes normales
du module, et il faut attendre les détails pour entendre parler de la
méthode select, qui passe pour une fonction d'utilisation avancée, rarement
utile.


C'est vrai : le synopsis comme l'exemple final n'utilisent que de la
surveillance en lecture. Et la documentation est assez succincte (elle
ne fait que présenter les méthodes dans l'ordre alphabétique).

Alors que c'est le contraire : l'usage normal est select, et
can_read/can_write sont des cas particuliers moins utiles.


Tout à fait d'accord.

À mon avis, une API plus intelligente aurait été d'avoir un paramètre de
mode à la méthode add, pour indiquer si on souhaite surveiller un fd donné
en lecture, en écriture ou les deux, et une seule méthode en tout et pour
tout pour faire le test.


Je pense qu'un retour en arrière sera maintenant difficile (pour des
raisons de compatibilité avec les scripts existants). Mais rien
n'empêche de proposer une amélioration de la doc et de l'API (en
rendant certaines méthodes "deprecated").

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>

Avatar
Sébastien Cottalorda
Paul Gaborit wrote in message :

Les méthodes distinctes sont utiles lorsqu'on n'attend que des
lectures, que des écritures ou que des exceptions.

La fonction 'select' gère le cas général et permet de récupérer
imméditatement les objets à traiter. Elle est vraiment *beaucoup* plus
simple d'usage que la fonction 'select' primitive.

En fait, ce module, bien utilisé, me semble très pratique et encapsule
les choses proprement (la manipulation des fd et des vecteurs de bits
n'est pas vraiment simples à faire). Mais, effectivement, il n'empêche
pas de faire n'importe quoi.



Je trouve que l'API est mal choisie, alors, et la documentation n'est
vraiment pas là pour améliorer les choses : rien qu'à lire le synopsis, on a
la très nette impression que can_read/can_write sont les méthodes normales
du module, et il faut attendre les détails pour entendre parler de la
méthode select, qui passe pour une fonction d'utilisation avancée, rarement
utile.

Alors que c'est le contraire : l'usage normal est select, et
can_read/can_write sont des cas particuliers moins utiles.

À mon avis, une API plus intelligente aurait été d'avoir un paramètre de
mode à la méthode add, pour indiquer si on souhaite surveiller un fd donné
en lecture, en écriture ou les deux, et une seule méthode en tout et pour
tout pour faire le test.


Votre débat me turlupine depuis deux jours.
J'ai pêché la technique de la boucle
while (1){
foreach ($select->can_read()){

}
foreach ($select->can_write()){

}
foreach ($select->has_exception()){

}
}
sur un serveur TCP, en mode non bloquant, dans le "Cookbook" de perl ou
bien dans "Total Perl" (presque pareil mais francisé).

Si j'ai bien tout compris, vous ne recommandez pas cette technique ???
Ne dois-je gérer que la méthode "can_read" en mode bloquant et lever une
interrupt gràce à ularm de Time::HiRes pour gérer les envois ?

Merci de bien vouloir m'éclairer, je ne voudrais pas me lourder sur la
base de la conception. L'application que je suis en train de développer
utilise massivement des sockets clients et des serveurs.
Si la technique n'est pas bonne, j'aimerais autant rectifier tout de suite.

Je développe un logiciel de contrôle d'accès pour des autocars de
tourisme (Entrée et Sortie d'un parking).
Chaque entrée et chaque sortie est équipé de 2 équipements différents:
* Une Borne à écran tactile (IHM),
* Un Système de Reconnaissance de plaques minéralogiques.
Chacun de ces 2 systèmes doit être relié à un processus MASTER: Le
Contrôle d'Accès : c'est lui qui autorise ou non l'accès à l'ouvrage.
Les 2 systèmes n'ont pas le même protocole (les messages ne sont pas du
tout les mêmes).
Voici comment je compte précéder:


Equipement1---------Socket1

Equipement2---------Socket2--+--+---Controle d'Accès
/
EquipementN---------SocketN Scripts Perl (Pilotage)


Pour des raisons de performance, je préfère que le Contrôle d'Accès ne
se charge pas de la vérification du format des messages, ni du pilotage
des équipements.
Je préfère laisser celà aux processus Socket.

Dans mon idée,

1-/ Chaque processus Socket = un serveur non forké, non bloquant. Cela
est dû au fait que je dois pouvoir envoyer des ordres directement aux
équipements, sans passer par le Contrôle d'Accès (Scripts Perl) : les
équipement doivent alors pouvoir me répondre (sans faire appel au
Contrôle d'Accès).

2-/ Le Contrôle d'Accès = un client qui se connecte à tous les processus
Socket en mode bloquant en lecture : il attend qu'on lui demande
d'autoriser ou non un accès, puis il répond.

3-/ Les Scripts Perl = des clients qui se connectent à l'équipement
désiré, envoient un ordre, et attendent le résultat (processus clients
bloqués en lecture).

Qu'en pensez-vous ?

Sébastien


Avatar
Nicolas George
Sébastien Cottalorda
wrote in message <42e7e999$0$18459$:
Votre débat me turlupine depuis deux jours.
J'ai pêché la technique de la boucle
<snip>

sur un serveur TCP, en mode non bloquant, dans le "Cookbook" de perl ou
bien dans "Total Perl" (presque pareil mais francisé).


Je n'ai pas les exemples sous la main. De deux choses l'une : soit ils
diffèrent subtilement de ce que vous indiquez, soit ils sont mauvais.

Si j'ai bien tout compris, vous ne recommandez pas cette technique ???


Non, jamais de la vie. Une règle universelle de la programmation sous Unix
est que tout programme autre qu'un programme de calcul intensif doit avoir
au moins un appel système bloquant dans sa boucle principale. Si ce n'est
pas le cas, le programme va parcourir sa boucle indéfiniment pour ne rien
faire, en consommant inutilement du temps de calcul et de la mémoire (un
processus bloqué dans un appel système peut être envoyé en swap, un
processus qui tourne en boucle moins).

Dans le cas d'un serveur synchrone avec un thread ou processus indépendant
par client, comme un serveur HTTP, SMTP, NNTP, etc., on procède souvent
ainsi :

while(1) {
read_request(); # bloquant
compute_response();
send_response(); # bloquant
}

Dans le cas d'un serveur qui doit parler à plusieurs clients à la fois dans
un même thread, par exemple un serveur IRC, ce modèle ne marche évidemment
pas : si le serveur est bloqué sur la lecture d'un client qui ne parle pas,
il reste indéfiniment, alors que d'autres clients parlent.

La solution pour ça est select (ou ses variantes : pselect pour une gestion
vaguement plus propre des signax, poll pour une interface un peu plus souple
et plus efficace, epoll sous Linux >= 2.5 pour de la haute performance s'il
y a beaucoup de clients, etc.) : select prend en argument des listes de
file-descriptors, et bloque jusqu'à ce qu'il se passe quelque chose sur l'un
ou l'autre de ces file-descriptors.

Pour chaque file-descriptor, select peut indépendemment attendre que des
données soient disponibles en lecture, qu'il soit possible d'écrire (si le
réseau est lent et qu'on envoit beaucoup de données, ce n'est pas clair),
ainsi que des situations « exceptionnelles », qui sont rarement
intéressantes. On peut en outre lui préciser un temps maximum pendant lequel
il doit bloquer (qui peut être zéro).

Prenons le cas simple, où il n'y a qu'à écouter les clients (et donc ni à
leur répondre, ni à faire quoi que ce soit d'auter à côté), ça donne ça :

while(1) {
select(<clients>, rien, rien, infini);
for (<chaque client indiqué comme prêt par select>) {
<lire les données de ce client>
<traiter la requête>
}
}

Le programme passera le plus clair de son temps bloqué (en consommant 0
resources) sur select. À noter que l'un des clients peut être une socket
passive, ça marche pareil.

Hélas, cette situation idéale ne marche jamais. Premier écueil : quasiment
aucun protocole ne se contente de requêtes d'un octet. Il faut souvent lire
une ligne entière, ou une taille fixée de données, et ça select ne le
garantit pas : la requête peut très bien avoir été fragmentée en deux
paquets, le premier est arrivé mais juste après le réseau est tombé. Si on
procède de la manière naïve décrite plus haut, das cette situation, on va se
retrovuer bloqué sur <lire les données du client> à attendre la deuxième
moitié de la requête.

Pour résoudre ça, on est à peu près obligé d'affubler chaque client d'un
tampon, et la boucle devient :

while(1) {
select(<clients>, rien, rien, infini);
for (<chaque client indiqué comme prêt par select>) {
<lire les données de ce client, les accumuler dans son tampon>
if(<le tampon contient une requête entière>) {
<traiter la requête>
}
}
}

À noter qu'en perl, ceci impose d'utiliser sysread et pas les fonctions
sympa du style readline/< >. D'ailleurs, c'est imposé également dans l'autre
sens : si deux requêtes arrivent d'un coup, perl lit les deux dans son
buffer interne, on en traite une, et au tour suivant, select bloque, car la
requête a déjà été lue (par perl).

Ça se complique encore si le serveur doit répondre aux clients, ce qui est
presque toujours le cas en fait. Dans le cas simple, on peut se dire que le
réseau est rapide, qu'il y a peu de données à envoyer, et que ce n'est pas
grave si les autres clients attendent quelquesinstants de temps en temps.
Dans ce cas, on peut simplement ajouter à la boucle :

if(<le tampon contient une requête entière>) {
<traiter la requête>
+ <répondre au client>
}

avec une écriture bloquante qui va en pratique rarement bloquer, et jamais
pour très longtemps.

Mais si les clients sont suceptibles d'être malveillants, cette solution
n'est pas acceptable : un client pourrait exprès faire plein de requêtes, et
ne jamais lire les réponses, ça finirait par saturer. Ce n'est pas non plus
envisageable s'il faut une réaction dans des délais prédéterminés.

Dans ce cas, on s'en tire encore avec un tampon :

while(1) {
select(<clients à lire>, <clients à qui on veut écrire>, rien, infini);
for (<chaque client indiqué comme prêt en lecture>) {
<lire les données de ce client, les accumuler dans son tampon de lecture>
if(<le tampon de lecture contient une requête entière>) {
<traiter la requête>
<mettre la réponse dans le tampon d'écriture>
}
}
for (<chaque client indiqué comme prêt en écriture>) {
<envoyer des données>
<les enlever du tampon d'écriture>
}
}

Ici, <clients à qui on veut écire> est la liste des sockets des clients dont
le tampon d'écriture n'est pas vide. Quant à <clients à lire>, ça peut être
tous les clients (dans le cas d'un serveur asynchrone), ou seulement ceux
dont le tampon d'écriture est vide (dans le cas d'un serveur où le
fonctionnement normal est que le client attende les réponses à ses
requêtes).

Enfin, le serveut veut vouloir faire des choses de sa propre initiative,
comme par exemple envoyer une sollicitation à un client qui a été inactif
pendant cinq minutes, ou le déconnecter. Dans ce cas, on utilise la
temporisation de select :

while(1) {
$timeout = <heure de la prochaine action prévue du serveur> - <maintenant>;
select(<clients à lire>, <clients à qui on veut écrire>, rien, $timeout);
if(<timeout>) {
<faire ce qui était prévu>
}
for (<chaque client indiqué comme prêt en lecture>) {
<lire les données de ce client, les accumuler dans son tampon de lecture>
if(<le tampon de lecture contient une requête entière>) {
<traiter la requête>
<mettre la réponse dans le tampon d'écriture>
}
}
for (<chaque client indiqué comme prêt en écriture>) {
<envoyer des données>
<les enlever du tampon d'écriture>
}
}

On arrive là à la structure presque la plus générique d'une boucle select
(pour faire complètement générique, il faudrait ajouter une gestion des
signaux). Quand on débute en programmation sous Unix, ça peut paraître
lourd, mais ça se fait bien, et on finit par s'écrire des bibliothèques qui
prennent l'essentiel en charge.

Ne dois-je gérer que la méthode "can_read" en mode bloquant et lever une
interrupt gràce à ularm de Time::HiRes pour gérer les envois ?


Non. Il ne faut pas utiliser alarm ! Ni une de ses variantes. alarm
fonctionne avec un signal, et l'API des signaux sous Unix est, il faut bien
l'avouer, à chier. Moins on en traite, mieux on se porte.

Par rapport aux autres appels système bloquants, select a un délai de
blocage réglable, il faut s'en servir.

Equipement1---------Socket1

Equipement2---------Socket2--+--+---Controle d'Accès
/
EquipementN---------SocketN Scripts Perl (Pilotage)


Je ne comprends pas ce diagramme : on ne voit pas ce qui est un programme,
ce qui est une connexion réseau ou simplement un câble pioté par un
gestionnaire de périphérique (soit dit en passant, certains périphériques,
typiquement un port série, peuvent être surveillés par select au même titre
qu'une connexion réseau).

Par exemple les « + » : que sont-ils ?

Qu'en pensez-vous ?


Sur le problème de fond, rien : la description de la problématique n'est pas
assez précise pour se faire une idée.

Sur la manière de l'aborder, je ne saurais trop conseiller la lecture de
quelques chapitres d'_Unix Network Programming_, essentiellement tous ceux
où il est question de serveur multiplexé (select) et d'entrées-sortires
non-bloquantes ou asynchrones. Je ne peux pas préciser les numéros parce que
j'ai laissé mon exemplaire à Dijon.

Avatar
Nicolas George
[XPost sur fco.unix, pas de fu2 pour le moment, parce que les réponses
peuvent concerner aussi bien perl que la programmation Unix ; merci
d'adapter.]

Sébastien Cottalorda
wrote in message <42e7e999$0$18459$:
Votre débat me turlupine depuis deux jours.
J'ai pêché la technique de la boucle
<snip>

sur un serveur TCP, en mode non bloquant, dans le "Cookbook" de perl ou
bien dans "Total Perl" (presque pareil mais francisé).


Je n'ai pas les exemples sous la main. De deux choses l'une : soit ils
diffèrent subtilement de ce que vous indiquez, soit ils sont mauvais.

Si j'ai bien tout compris, vous ne recommandez pas cette technique ???


Non, jamais de la vie. Une règle universelle de la programmation sous Unix
est que tout programme autre qu'un programme de calcul intensif doit avoir
au moins un appel système bloquant dans sa boucle principale. Si ce n'est
pas le cas, le programme va parcourir sa boucle indéfiniment pour ne rien
faire, en consommant inutilement du temps de calcul et de la mémoire (un
processus bloqué dans un appel système peut être envoyé en swap, un
processus qui tourne en boucle moins).

Dans le cas d'un serveur synchrone avec un thread ou processus indépendant
par client, comme un serveur HTTP, SMTP, NNTP, etc., on procède souvent
ainsi :

while(1) {
read_request(); # bloquant
compute_response();
send_response(); # bloquant
}

Dans le cas d'un serveur qui doit parler à plusieurs clients à la fois dans
un même thread, par exemple un serveur IRC, ce modèle ne marche évidemment
pas : si le serveur est bloqué sur la lecture d'un client qui ne parle pas,
il reste indéfiniment, alors que d'autres clients parlent.

La solution pour ça est select (ou ses variantes : pselect pour une gestion
vaguement plus propre des signax, poll pour une interface un peu plus souple
et plus efficace, epoll sous Linux >= 2.5 pour de la haute performance s'il
y a beaucoup de clients, etc.) : select prend en argument des listes de
file-descriptors, et bloque jusqu'à ce qu'il se passe quelque chose sur l'un
ou l'autre de ces file-descriptors.

Pour chaque file-descriptor, select peut indépendemment attendre que des
données soient disponibles en lecture, qu'il soit possible d'écrire (si le
réseau est lent et qu'on envoit beaucoup de données, ce n'est pas clair),
ainsi que des situations « exceptionnelles », qui sont rarement
intéressantes. On peut en outre lui préciser un temps maximum pendant lequel
il doit bloquer (qui peut être zéro).

Prenons le cas simple, où il n'y a qu'à écouter les clients (et donc ni à
leur répondre, ni à faire quoi que ce soit d'auter à côté), ça donne ça :

while(1) {
select(<clients>, rien, rien, infini);
for (<chaque client indiqué comme prêt par select>) {
<lire les données de ce client>
<traiter la requête>
}
}

Le programme passera le plus clair de son temps bloqué (en consommant 0
resources) sur select. À noter que l'un des clients peut être une socket
passive, ça marche pareil.

Hélas, cette situation idéale ne marche jamais. Premier écueil : quasiment
aucun protocole ne se contente de requêtes d'un octet. Il faut souvent lire
une ligne entière, ou une taille fixée de données, et ça select ne le
garantit pas : la requête peut très bien avoir été fragmentée en deux
paquets, le premier est arrivé mais juste après le réseau est tombé. Si on
procède de la manière naïve décrite plus haut, das cette situation, on va se
retrovuer bloqué sur <lire les données du client> à attendre la deuxième
moitié de la requête.

Pour résoudre ça, on est à peu près obligé d'affubler chaque client d'un
tampon, et la boucle devient :

while(1) {
select(<clients>, rien, rien, infini);
for (<chaque client indiqué comme prêt par select>) {
<lire les données de ce client, les accumuler dans son tampon>
if(<le tampon contient une requête entière>) {
<traiter la requête>
}
}
}

À noter qu'en perl, ceci impose d'utiliser sysread et pas les fonctions
sympa du style readline/< >. D'ailleurs, c'est imposé également dans l'autre
sens : si deux requêtes arrivent d'un coup, perl lit les deux dans son
buffer interne, on en traite une, et au tour suivant, select bloque, car la
requête a déjà été lue (par perl).

Ça se complique encore si le serveur doit répondre aux clients, ce qui est
presque toujours le cas en fait. Dans le cas simple, on peut se dire que le
réseau est rapide, qu'il y a peu de données à envoyer, et que ce n'est pas
grave si les autres clients attendent quelquesinstants de temps en temps.
Dans ce cas, on peut simplement ajouter à la boucle :

if(<le tampon contient une requête entière>) {
<traiter la requête>
+ <répondre au client>
}

avec une écriture bloquante qui va en pratique rarement bloquer, et jamais
pour très longtemps.

Mais si les clients sont suceptibles d'être malveillants, cette solution
n'est pas acceptable : un client pourrait exprès faire plein de requêtes, et
ne jamais lire les réponses, ça finirait par saturer. Ce n'est pas non plus
envisageable s'il faut une réaction dans des délais prédéterminés.

Dans ce cas, on s'en tire encore avec un tampon :

while(1) {
select(<clients à lire>, <clients à qui on veut écrire>, rien, infini);
for (<chaque client indiqué comme prêt en lecture>) {
<lire les données de ce client, les accumuler dans son tampon de lecture>
if(<le tampon de lecture contient une requête entière>) {
<traiter la requête>
<mettre la réponse dans le tampon d'écriture>
}
}
for (<chaque client indiqué comme prêt en écriture>) {
<envoyer des données>
<les enlever du tampon d'écriture>
}
}

Ici, <clients à qui on veut écire> est la liste des sockets des clients dont
le tampon d'écriture n'est pas vide. Quant à <clients à lire>, ça peut être
tous les clients (dans le cas d'un serveur asynchrone), ou seulement ceux
dont le tampon d'écriture est vide (dans le cas d'un serveur où le
fonctionnement normal est que le client attende les réponses à ses
requêtes).

Enfin, le serveut veut vouloir faire des choses de sa propre initiative,
comme par exemple envoyer une sollicitation à un client qui a été inactif
pendant cinq minutes, ou le déconnecter. Dans ce cas, on utilise la
temporisation de select :

while(1) {
$timeout = <heure de la prochaine action prévue du serveur> - <maintenant>;
select(<clients à lire>, <clients à qui on veut écrire>, rien, $timeout);
if(<timeout>) {
<faire ce qui était prévu>
}
for (<chaque client indiqué comme prêt en lecture>) {
<lire les données de ce client, les accumuler dans son tampon de lecture>
if(<le tampon de lecture contient une requête entière>) {
<traiter la requête>
<mettre la réponse dans le tampon d'écriture>
}
}
for (<chaque client indiqué comme prêt en écriture>) {
<envoyer des données>
<les enlever du tampon d'écriture>
}
}

On arrive là à la structure presque la plus générique d'une boucle select
(pour faire complètement générique, il faudrait ajouter une gestion des
signaux). Quand on débute en programmation sous Unix, ça peut paraître
lourd, mais ça se fait bien, et on finit par s'écrire des bibliothèques qui
prennent l'essentiel en charge.

Ne dois-je gérer que la méthode "can_read" en mode bloquant et lever une
interrupt gràce à ularm de Time::HiRes pour gérer les envois ?


Non. Il ne faut pas utiliser alarm ! Ni une de ses variantes. alarm
fonctionne avec un signal, et l'API des signaux sous Unix est, il faut bien
l'avouer, à chier. Moins on en traite, mieux on se porte.

Par rapport aux autres appels système bloquants, select a un délai de
blocage réglable, il faut s'en servir.

Equipement1---------Socket1

Equipement2---------Socket2--+--+---Controle d'Accès
/
EquipementN---------SocketN Scripts Perl (Pilotage)


Je ne comprends pas ce diagramme : on ne voit pas ce qui est un programme,
ce qui est une connexion réseau ou simplement un câble pioté par un
gestionnaire de périphérique (soit dit en passant, certains périphériques,
typiquement un port série, peuvent être surveillés par select au même titre
qu'une connexion réseau).

Par exemple les « + » : que sont-ils ?

Qu'en pensez-vous ?


Sur le problème de fond, rien : la description de la problématique n'est pas
assez précise pour se faire une idée.

Sur la manière de l'aborder, je ne saurais trop conseiller la lecture de
quelques chapitres d'_Unix Network Programming_, essentiellement tous ceux
où il est question de serveur multiplexé (select) et d'entrées-sortires
non-bloquantes ou asynchrones. Je ne peux pas préciser les numéros parce que
j'ai laissé mon exemplaire à Dijon.

1 2