Indy Écrire de mise en mémoire Tampon / Efficacité de la communication TCP
Je sais, je pose beaucoup de questions...mais comme un nouveau développeur delphi, je continue de tomber sur toutes ces questions 🙂
Il s'agit de la communication TCP à l'aide d'indy 10. Pour rendre la communication efficace, j'ai le code d'un client demande d'opération à un seul octet (dans la plupart des cas, suivis par les autres octets de données de cours, mais dans ce cas, un seul octet). Le problème est que
var Bytes : TBytes;
...
SetLength (Bytes, 1);
Bytes [0] := OpCode;
FConnection.IOHandler.Write (Bytes, 1);
ErrorCode := Connection.IOHandler.ReadByte;
ne pas envoyer l'octet immédiatement (au moins les serveurs exécuter le gestionnaire n'est pas invoquée). Si je change de '1' à '9' par exemple, tout fonctionne bien. Je suppose que Indy tampons sortant octets et a essayé de désactiver l'écriture de la mise en mémoire tampon avec
FConnection.IOHandler.WriteBufferClose;
mais il n'a pas aidé. Comment puis-je envoyer un seul octet et assurez-vous qu'il est immédiatement envoyé? Et - je ajouter une autre petite question ici - ce qui est le meilleur moyen d'envoyer un nombre entier à l'aide d'indy? Malheureusement je ne trouve pas de fonction comme WriteInteger dans le IOHandler de TIdTCPServer...et
WriteLn (IntToStr (SomeIntVal))
semble pas très efficace pour moi. Cela fait-il une différence si je utiliser plusieurs commandes d'écriture dans une ligne ou d'emballer les choses ensemble dans un tableau d'octets et de l'envoyer en une fois?
Merci pour toute les réponses!
EDIT: j'ai ajouté un soupçon que je suis à l'aide d'Indy 10, puisqu'il semble y avoir des changements importants concernant la lecture et l'écriture des procédures.
Cette commande est une exception. La plupart des commandes ajouter plus d'octets pour les paramètres de la commande. J'ai pensé qu'il ne pouvait pas être mauvais pour emballer les choses le plus près possible. Ou je me trompe ici?
Aussi longtemps que votre bloc de données s'inscrit dans un paquet TCP, il ne devrait pas faire beaucoup de différence. Le texte des protocoles basés sur otoh, que sont d'une grande aide quand il s'agit de débogage de trucs.
J'ai posté une question dans le stackoverflow.com/questions/2440926/... qui peuvent être liés d'une certaine façon, alors j'ai pensé que je voudrais mentionner ici au cas où quelqu'un a vu quelque chose de semblable.
OriginalL'auteur jpfollenius | 2009-03-03
Vous devez vous connecter pour publier un commentaire.
Écrire tampon est désactivé par défaut. Vous pouvez le vérifier écrire de mise en mémoire tampon pour voir s'il est actif dans votre code par les tests de la fConnection.IOHandler.WriteBufferingActive propriété.
Aussi loin que la meilleure façon d'envoyer un entier... "ça dépend" sur votre protocole et les objectifs généraux. Plus précisément, l'utilisation FConnection.IOHandler.Write() qu'il y a des méthodes surchargées d'écrire juste au sujet de n'importe quel type de données, y compris un nombre entier.
Prises de IdIOHandler:
Une autre question était "est-il une différence si je utiliser plusieurs commandes d'écriture dans une ligne ou d'emballer les choses ensemble dans un tableau d'octets et de l'envoyer en une fois?" Pour la majorité des cas, oui, cela fait une différence. Pour les très stressé serveurs vous allez avoir à s'impliquer davantage dans la façon dont les octets sont envoyés en arrière, mais à ce niveau, vous devriez abstraction de votre envoie dans un protocole séparé type de classe qui construit l'envoi de données et l'envoie dans un éclat et un protocole de réception qui reçoit un bouquet de données et des processus comme une unité complète, au lieu de casser les choses pour l'envoi/la réception d'un entier, d'un personnage, tableau d'octets, etc..
Comme un très approximative exemple rapide:
Puis de l'envoyer via:
De l'autre côté, vous pouvez recevoir des données par le biais d'Indy, puis
Si vous utilisez Indy en écriture intégré de mise en mémoire tampon, vous n'avez pas besoin de sérialiser les données manuellement. Et vous devriez certainement PAS utiliser de chaînes pour la sérialisation, de toute façon, surtout quand on travaille avec Indy 10 et son nouveau Unicode capacités. Si vous souhaitez sérialiser manaully, puis utilisez TIdBytes à la place.
Unicode dans la communication pour moi, et beaucoup de gens aux états-UNIS, est moins utile. D'ailleurs, je préfère utiliser des chaînes pour la sérialisation de TidBytes. Je n'ai jamais fini à l'aide d'Indy 10 pour quelque chose d'important - Indy9 si Indy.
OriginalL'auteur Darian Miller
Je ne suis pas familier avec Indy, mais vous voudrez peut-être regarder autour de son API pour une option TCP_NODELAY (vous pouvez filtrer les Indy source arbre pour quelque chose comme ça - insensible à la casse pour le "retard" devrait le faire.)
Edit: Rob Kennedy a souligné que la propriété que je faisais référence est
TIdIOHandlerSocket.UseNagle
- merci!Le problème est inhérent à la nature de TCP. TCP garantit la livraison des données dans le même ordre que a été émis mais ne pas garantir les frontières de message. En d'autres termes, le système d'exploitation de la source, de la cible, et tous les routeurs sur le chemin libre à fusionner les paquets de la connexion ou de fragment. Vous devez examiner une transmission TCP comme un ruisseau, pas comme une série de paquets individuels. Ainsi, vous aurez à mettre en œuvre un mécanisme qui soit délimiter les messages individuels (par la magie de l'octet, par exemple, vous devez vous échapper si il peut également se produire dans votre message de données), ou vous pouvez envoyer la longueur de ce message, d'abord, puis le message réel.
J'ai toujours utilisé l'UDP couplé avec une naïveté ACK/retransmission régime quand j'ai besoin d'envoyer des messages où le message frontière était important, comme c'est votre cas. Voudrez peut-être prendre ça en compte. UDP est beaucoup mieux adapté pour les messages de commande.
Yup, Nagle - merci, Rob. J'ai édité le post en conséquence.
OriginalL'auteur Mihai Limbășan
Semble que vous devez rincer votre tampon. Essayez ceci:
Si vous ne voulez pas une mémoire tampon d'écriture, utilisez ceci:
Selon l'aider, ce qui appelle d'abord ClearWriteBuffer, à effacer la mémoire tampon, puis appelle CloseWriteBuffer.
La meilleure façon d'envoyer un nombre entier (à l'aide d'Indy 10) est à l'aide de TIdIOHandler.Écrire (selon Indy 10 aider à Écrire est surchargé de gérer différents types de données, y compris des Entiers)
...et concernant votre montage avec WriteInteger: je pense que vous êtes en utilisant Indy 9. Mon IOHandler ne contient pas une telle méthode.
Essayez d'utiliser le TIdTCPConnection méthodes d'écriture au lieu de la IOHandler directement, peut-être que cela fait une différence. Je présume que vous appelez FlushWriteBuffer après avoir Écrit les données et avant de lire la réponse.
C'est parce que je ne suis pas en utilisant la IOHandler, mais la classe de Connexion (FConnection dans votre cas), et oui, je suis à la recherche lors de l'Indy 9 de l'aide.
Votre présomption est correct 😉 En Indy 10 il n'y a pas de méthodes d'écriture dans la connexion TCP en plus WriteHeader et WriteRFCStrings.
OriginalL'auteur The_Fox