Bonjour,
Dans le cadre d'un client / serveur, je suis amené a gérer plusieurs clients en lecture et en écriture. J'utilise la fonction select, qui prend un fd_set de lecture, d'écriture et la valeur max présente dans les fds.
Problématique : si un client se connecte, s'authentifie, je lui envoi des données régulièrement. Si le client reste connecté mais ne read plus (volontairement, il peut mais il le fait pas), et que le serveur veut lui envoyer quelques choses, select me dira que je peux write. Puisque mon client ne read pas, je vais accumuler dans le buffer d'écriture de la socket, toutes les données envoyées. La taille maximale de ce buffer est de 64k. Lorsque le buffer d'écriture de la socket sera rempli, select ne me permettra plus d'écrire. Ce cas là est géré par select, c'est parfait.
Le vrai problème est si select m'autorise à écrire, mais que la quantité de ce que je veux écrire est supérieur à la taille qu'il reste dans le buffer d'écriture de la socket, mon write va être bloquant. Et le méchant client aura simplement fait planter mon server en ne lisant simplement plus ce que je lui envoi.
Comment je peux répondre à cette problématique ?
J'ai pensé à :
- utiliser ioctl avec un incrémenteur : dès que je write j'additionne la longueur dans cet incrémenteur, dès que j'arrive vers les 60k (mon buffer fait 4k), je fais un FION_WRITE qui me dis combien d'octets sont dans le buffer d'écriture de la socket, et je peux en déduire le nombre d'octets max à écrire et agir en conséquence.
- connaître la taille minimale du buffer d'écriture pour que select considère que je peux write, et split chacun de mes messages à une taille inférieur.
La première solution est extrèmement couteuse et plutôt lourde à implémenter, mais je ne sais pas comment connaître la taille minimal qui permet au trigger de select de détecter que je peux write sur telle ou telle socket.
J'ai exploré différentes pistes :
- man de select, select_tu, et tous les autres man lié à select(listen, socket, bind, …)
- farfouillage dans les .h qu'utilise select
- exploration du code source de select.
La fonction select appelle core_sys_select. La fonction core_sys_select appelle do_select. Le seul moment où do_select modifie le pointeur du fd_set de write c'est dans un for infinie, qui contient un for qui boucle sur les fds. Tout semble parfait. Le seul moment où il modifie le pointeur passé à select pour surveiller les write, c'est sur une condition à base de POLLSET. C'est une macro contenant plusieurs infos. La plus haute valeur de cette macro étant 256, donc je comprend pas.
Si quelqu'un à cette information, ou si vous avez des remarques / idées…
D'avance, merci.
krostar.