2009-10-07 10 views
9

Quand j'envoie()/write() un message sur un flux tcp, comment puis-je savoir si ces octets ont été livrés avec succès?Déterminer si un message sur tcp a été livré

Le destinataire accuse réception des octets via tcp, de sorte que la pile tcp de l'expéditeur doit en être informée. Mais quand j'envoie() quelques octets, send() retourne immédiatement, même si le paquet n'a pas pu (encore) être livré, je l'ai testé sous Linux 2.6.30 en utilisant strace sur netcat, en tirant mon câble réseau avant envoyer des octets.

Je suis juste en train de développer une application où il est très important de savoir si un message a été livré, mais l'implémentation des fonctionnalités tcp ("ack pour le message # 123") est maladroite, il doit y avoir un meilleur moyen.

Répondre

19

L'envoi TCP ne sait quand les données ait pu être confirmée autre extrémité, mais la seule raison pour laquelle il fait cela est que il sait quand il peut rejeter les données (parce que quelqu'un d'autre est maintenant responsable de l'avoir à l'application de l'autre côté).

Il ne fournit généralement pas cette information à l'application d'envoi, car (en dépit des apparences) il ne serait pas vraiment signifie beaucoup à l'application d'envoi. L'accusé de réception ne signifie pas que l'application réceptrice a reçu les données et a fait quelque chose de sensé avec cela - tout ce que cela signifie, c'est que le TCP expéditeur n'a plus à s'en soucier. Les données peuvent toujours être en transit - dans un serveur proxy intermédiaire, par exemple, ou dans la pile TCP de réception."Data received received" est vraiment un concept au niveau de l'application - ce que cela signifie varie en fonction de l'application (par exemple, pour de nombreuses applications, il serait logique de considérer les données "reçues" une fois qu'elles ont été synchronisées disque sur le côté récepteur). Cela signifie donc que vous devez l'implémenter vous-même, car en tant que développeur d'applications, vous êtes vraiment le seul à même de savoir comment le faire raisonnablement pour votre application.

8

Avoir le récepteur renvoie un accusé de réception est la meilleure façon, même si elle "se sent maladroite". Rappelez-vous que l'IP peut diviser vos données en plusieurs paquets et les réassembler, et cela peut être fait plusieurs fois le long d'une transmission si plusieurs routeurs ont des MTU différentes, et donc votre concept de «paquet» et TCP peut être en désaccord. Il vaudrait mieux envoyer votre "paquet", qu'il s'agisse d'une chaîne, d'un objet sérialisé ou de données binaires, et demander au récepteur de faire les vérifications nécessaires pour le faire apparaître, puis renvoyer un accusé de réception.

+0

Les faits sont corrects, mais je n'aime pas le phrasé. TCP est un protocole fiable, vous en entendrez parler ** si la transmission échoue. Le fait que vous n'avez pas besoin de demander un ACK du côté distant est une fonctionnalité, pas un bug. La "meilleure" façon de gérer cela est d'ignorer le problème au niveau des appels système et des octets. Si vous avez besoin d'un résultat, faites-le au niveau du protocole, pas au niveau des sockets. –

6

Le protocole TCP essaie très fort de s'assurer que vos données arrivent. S'il y a un problème de réseau, il retransmettra les données plusieurs fois. Cela signifie que tout ce que vous envoyez est tamponné et qu'il n'y a pas moyen de s'assurer qu'il est arrivé (il y aura un timeout 2 minutes plus tard si le réseau est en panne).

Si vous avez besoin d'un retour rapide, utilisez le protocole UDP. Il n'utilise aucune surcharge TCP, mais vous devez gérer vous-même tous les problèmes.

+0

Oui, de par sa conception, il est fiable et ordonné – RichardOD

3

La couche d'application n'a aucun contrôle sur les notifications des couches inférieures (telles que la couche Transport) à moins qu'elles ne soient spécifiquement fournies - c'est par conception. Si vous voulez savoir ce que fait TCP sur un niveau par paquet, vous devez vous renseigner sur la couche sur laquelle TCP fonctionne; cela signifie gérer les en-têtes TCP et les données ACK. Cependant, tout protocole que vous finissez par utiliser pour transporter votre charge utile peut être utilisé pour transmettre des messages par le biais de cette charge utile. Donc, si vous vous sentez gêné en utilisant les bits d'un en-tête TCP pour le faire, il suffit de le configurer dans votre application. Par exemple:

A: Send 450 Bytes 
B: Recv 450 Bytes 
B: Send 'I got 450 Bytes' 
A: Recv 'B got the full message' 
A: Continue 
1

Cela ressemble à SCTP pourrait être quelque chose à regarder; Je pense que cela devrait soutenir ce que vous voulez. L'alternative semble être de passer à UDP, et si vous passez des protocoles de toute façon ...

3

Même s'il est allé aussi loin que la couche TCP, il n'y a aucune garantie qu'il ne se trouve pas dans le tampon de l'application, alors l'application a planté avant de pouvoir le traiter. Utilisez un accusé de réception, c'est ce que tout le reste fait (par exemple SMTP)

Questions connexes