web-dev-qa-db-fra.com

Existe-t-il un moyen de vider un socket POSIX?

Existe-t-il un appel standard pour rincer le côté émission d'un socket POSIX jusqu'à l'extrémité distante ou cela doit-il être implémenté dans le cadre du protocole de niveau utilisateur? J'ai regardé autour des en-têtes habituels mais je n'ai rien trouvé.

36
Gordon Wrigley

Pour les sockets de domaine Unix, vous pouvez utiliser fflush(), mais je pense que vous parlez probablement de sockets réseau. Il n'y a pas vraiment de concept pour les vider. Les choses les plus proches sont:

  1. À la fin de votre session, appelez shutdown(sock, SHUT_WR) pour fermer les écritures sur le socket.

  2. Sur TCP sockets, désactivation de l'algorithme Nagle avec sockopt TCP_NODELAY, ce qui est généralement une idée terrible qui ne fera pas de manière fiable ce que vous voulez, même si elle semble s'en occuper lors de l'enquête initiale.

Il est très probable que la gestion de tout problème nécessitant une "vidange" au niveau du protocole utilisateur sera la bonne chose.

16
chaos

Qu'en est-il de la configuration de TCP_NODELAY et de sa réinitialisation? Cela pourrait probablement être fait juste avant d'envoyer des données importantes, ou lorsque nous aurons fini d'envoyer un message.

send(sock, "notimportant", ...);
send(sock, "notimportant", ...);
send(sock, "notimportant", ...);
int flag = 1; 
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
send(sock, "important data or end of the current message", ...);
flag = 0; 
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));

Comme le disent les pages de manuel Linux

TCP_NODELAY ... la définition de cette option force un vidage explicite de la sortie en attente ...

Il serait donc probablement préférable de le définir après le message, mais je ne sais pas comment cela fonctionne sur d'autres systèmes

25
fantastory

Dans la RFC 1122, le nom de la chose que vous recherchez est "Push". Bien que je ne connaisse aucun TCP API qui implémente "Push".

Quelques réponses et commentaires concernent l'algorithme Nagle. La plupart d'entre eux semblent supposer que l'algorithme Nagle retarde chaque envoi. Cette hypothèse n'est pas correcte. Nagle retarde l'envoi uniquement lorsqu'un paquet précédent n'a pas encore été reconnu ( http://www.unixguide.net/network/socketfaq/2.11.shtml ).

Pour simplifier un peu: TCP essaie d'envoyer le premier paquet (d'une ligne de paquets) immédiatement mais retarde les paquets suivants jusqu'à ce qu'un délai soit atteint ou que le premier paquet soit reconnu - selon la première éventualité.

Une solution consiste à éviter ces "paquets ultérieurs". Si vos appels d'application envoient () plus d'une fois pour transmettre une seule demande composée, essayez de réécrire votre application. Assemblez la requête dans l'espace utilisateur, puis appelez send(). Une fois que.

De plus, lorsque le tampon d'envoi contient suffisamment de données pour remplir la taille maximale d'un paquet réseau, Nagle ne tarde pas non plus. Cela signifie que Nagle ne retarde pas (vraiment) un envoi groupé, même si vous send() les données groupées en petits morceaux.

8
hagello

Il n'y a aucun moyen que je connaisse dans l'interface de socket TCP/IP standard pour vider les données "jusqu'à l'extrémité distante" et s'assurer qu'elles ont bien été reconnues.

D'une manière générale, si votre protocole a besoin d'un transfert de données "en temps réel", la meilleure chose à faire est généralement de définir la setsockopt() de TCP_NODELAY. Cela désactive l'algorithme Nagle dans la pile de protocoles et les écritures () ou send () sur le socket mappent plus directement aux envois sur le réseau .... au lieu d'implémenter des retards d'envoi en attendant que plus d'octets soient disponibles et en utilisant tous les TCP temporisateurs de niveau pour décider quand envoyer. REMARQUE: la désactivation de Nagle ne désactive pas la fenêtre coulissante TCP ou autre), il est donc toujours sûr de le faire. ... mais si vous n'avez pas besoin des propriétés "en temps réel", la surcharge de paquets peut augmenter considérablement.

Au-delà de cela, si les mécanismes de socket normaux TCP ne correspondent pas à votre application, vous devez généralement vous rabattre sur l'utilisation d'UDP et la création de vos propres fonctionnalités de protocole sur les propriétés de base d'envoi/réception d'UDP. . Ceci est très courant lorsque votre protocole a des besoins spéciaux, mais ne sous-estimez pas la complexité de bien le faire et de le rendre stable et fonctionnel dans toutes les applications, mais relativement simples. Comme point de départ, une étude approfondie des fonctionnalités de conception de TCP mettra en lumière bon nombre des questions qui doivent être examinées.

7
Tall Jeff

Je pense qu'il serait extrêmement difficile, voire impossible à mettre en œuvre correctement. Quelle est la signification de "flush" dans ce contexte? Octets transmis au réseau? Octets reconnus par le récepteur TCP? Octets transmis à l'application en mode utilisateur du récepteur? Octets entièrement traités par l'application en mode utilisateur?

On dirait que vous devez le faire au niveau de l'application ...

1
Arkadiy

TCP ne fournit que le meilleur effort possible, donc le fait d'avoir tous les octets quittent la machine A est asynchrone et tous ont été reçus sur la machine B. La pile de protocoles TCP/IP le sait, bien sûr, mais je n'en connais aucun moyen d'interroger la pile TCP pour savoir si tout ce qui a été envoyé a été reconnu.

La manière la plus simple de traiter la question est de loin au niveau de l'application. Ouvrez un second TCP pour agir comme canal de retour et demandez au partenaire distant de vous envoyer un accusé de réception pour avoir reçu les informations souhaitées. Cela coûtera le double mais sera complètement portable et économisera vous des heures de programmation.

0
Norman Ramsey

Vous pouvez définir l'option tcp SO_LINGER pour définir un certain délai, puis fermer le socket afin de vous assurer que toutes les données ont été envoyées (ou détecter l'échec de le faire) lors de la fermeture d'une connexion. En dehors de cela, TCP est un protocole "au mieux", et il ne fournit aucune garantie réelle que les données atteindront réellement la destination (contrairement à ce que certains semblent croire), il essaie simplement de le faire livrer dans le bon ordre et le plus tôt possible.

0
user1402866