Traitement des sockets TCP non bloquants – Comment détecter un blocage avant d’écrire sur le socket

J’écris actuellement une application proxy qui lit un socket et écrit sur un autre. Les deux sont définis comme non bloquants, permettant à plusieurs paires de sockets d’être gérées.

Pour contrôler un stream correct entre les sockets, l’application ne doit PAS lire à partir du socket source si l’écriture sur le socket cible peut être bloquée. L’idée est bonne, cependant je n’ai trouvé aucun moyen de détecter un état bloquant du socket cible sans écrire au préalable … et ce n’est pas ce qui est nécessaire.

Je connais une option pour utiliser SIOCOUTQ (en utilisant ioctl() ) et calculer le tampon restant, mais cela semble moche comparé à une simple vérification si le socket cible est prêt pour l’écriture.

Je suppose que je peux aussi utiliser select() uniquement pour ce socket, mais c’est un gaspillage considérable d’un appel système aussi lourd.

select ou poll devrait pouvoir vous donner les informations.
Je suppose que vous en utilisez déjà un pour détecter laquelle de vos sockets de lecture contient des données
Lorsque vous avez une prise de lecture disponible en lecture, remplacez-la par la prise d’écriture correspondante (mais mettez-la dans le fds d’écriture bien sûr), puis appelez à nouveau la select . Ensuite, si le socket d’écriture est disponible, vous pouvez lire et écrire.

Notez qu’il est possible que le socket d’écriture soit prêt à recevoir des données, mais pas autant que vous le souhaitez. Donc, vous pourriez peut-être lire 100 octets et n’en écrire que 50.

Merci à tous pour les commentaires.

Résumant tous les commentaires et réponses jusqu’à maintenant:

Directement à la question, le seul moyen connu de détecter le blocage d’un socket lors d’une tentative d’écriture consiste à select / poll / epoll .

L’objective initial était de créer un proxy, qui lit à partir d’un socket et écrit dans un autre, en maintenant un bon équilibre entre eux (lecture au même taux d’écriture et inversement) et en n’utilisant aucun tampon important. Pour cela, les options suivantes ont été présentées:

  1. Utilisez SIOCOUTQ pour savoir combien de mémoire tampon rest sur le socket de destination et ne transmettez rien d’autre. Comme @ugoren l’a souligné , cela présente l’inconvénient de ne pas être fiable, principalement parce qu’entre les lectures, le calcul et la tentative d’écriture de la valeur réelle peuvent changer. Il introduit également des problèmes d’attente occupée s’il est mal géré. Je suppose que si cette technique devait être utilisée, elle devrait être suivie d’une méthode plus fiable pour une protection totale.

  2. Utilisation de select / poll / epoll et ajout d’un petit tampon limité par socket de lecture: Initialement, tous les sockets de lecture sont ajoutés au poll . Une fois prêt pour la lecture, nous le lisons dans une taille de tampon limitée, puis retirons le socket de lecture du poll et ajoute à la place le socket de destination pour l’écriture, lorsque nous retournons au poll et que nous détectons que le socket de destination est prêt pour l’écriture, nous écrivons le tampon, si toutes les données ont été acceptées par le socket, nous supprimons le socket de destination. l’interrogation et renvoyer le socket de lecture. L’inconvénient est que nous augmentons le nombre d’appels système (ajout / suppression du poll / select ) et que nous devons conserver un tampon interne par socket. Cela semble être l’approche privilégiée et une optimisation pourrait être ajoutée pour essayer de réduire le nombre d’appels aux appels système (par exemple, essayer d’écrire juste après avoir lu le socket de lecture, et seulement s’il rest quelque chose à faire.

Merci encore à tous pour votre participation à cette discussion, cela m’a beaucoup aidé à commander les idées.