Tamponner les données de l'octet en C #
Mon application lit les octets à partir d'un socket TCP et les besoins de tampon, de sorte que je peux extraire des messages plus tard. En raison de la nature de TCP que je puisse obtenir partielle ou plusieurs messages dans un lire, donc après la lecture de chaque je tiens à inspecter la mémoire tampon et d'extraire autant de messages complets sont disponibles.
Donc je veux une classe qui me permet de faire ce qui suit:
- ajouter arbitraire byte[] données
- inspecter le contenu sans le consommer, en particulier le contrôle de la quantité de contenu et aussi la recherche de l'existence d'un certain octet ou d'octets
- extraire et de consommer une partie des données comme un byte[], tout en laissant le reste là-bas pour un avenir lire
J'espère que ce que je veux peut être fait avec 1 ou plusieurs classes existantes dans le .NET de la bibliothèque, mais je ne suis pas sûr. Système.IO.MemoryStream y regarde de plus près à ce que je veux, mais (a) il n'est pas clair de savoir si c'est adapté à être utilisé comme un tampon (la lecture des données retirés à partir de la capacité?) et (b) les lectures et les écritures semblent arriver à la même place - "La position actuelle d'un flux de données est la position à laquelle la prochaine opération de lecture ou écriture pourrait avoir lieu". - ce qui n'est pas ce que je veux. J'ai besoin d'être écrit à la fin et de la lecture à partir de l'avant.
source d'informationauteur Kylotan
Vous devez vous connecter pour publier un commentaire.
Il suffit d'utiliser un grand tableau d'octets et de la Matrice.La copie, il devrait faire l'affaire.
Si non, utilisez
List<byte>
.Si vous utilisez le tableau que vous avez à mettre en œuvre un index (où vous copiez des données supplémentaires) vous-même (même pour vérifier le contenu de taille), mais il est simple.
Si vous êtes intéressés: ici est une simple mise en œuvre d'un "tampon cyclique". Le test doit être exécuté (j'ai jeté un couple de test de l'unité à elle, mais il n'a pas vérifier tous les de chemin critique):
Veuillez noter: le code "consomme" à la lecture si vous ne voulez pas qu'il suffit de retirer le "_startIndex = ..." de pièces (ou de faire une surcharge de paramètre facultatif et de contrôler ou de quoi que ce soit).
Je vous suggère d'utiliser
MemoryStream
sous le capot, mais l'encapsuler dans une autre classe qui stocke:MemoryStream
Il exposera ensuite:
MemoryStream
et mise à jour de toutes les variables. (Vous ne voulez probablement pas à copier le tampon sur chaque consommer de la demande).Remarque que rien de tout cela va être thread-safe, sans synchronisation supplémentaire.
Voici une autre mise en œuvre d'un tampon que j'ai écrit il y a longtemps:
Venir à cette fin, mais pour la postérité:
Quand j'ai fait cela dans le passé, j'ai prendre une légère approche différente. Si vos messages ont un en-tête fixe la taille (qui vous indique le nombre d'octets dans le corps), et en gardant à l'esprit les flux réseau est déjà de mise en mémoire tampon, j'ai effectuer l'opération en deux phases:
Il exploite le fait que - pour un cours d'eau lorsque vous demandez 'n' octets que vous ne serez jamais plus dos, de sorte que vous pouvez ignorer les nombreuses opps j'ai lu trop, permettez-moi de mettre ces de côté jusqu'à la prochaine fois".
Maintenant, ce n'est pas toute l'histoire, pour être juste. J'ai eu un sous-jacent de classe wrapper sur le ruisseau de gérer des problèmes de fragmentation (c'est à dire si a demandé 4 octets, ne pas revenir jusqu'à 4 octets reçus, ou stream fermé). Mais ce bit est assez facile.
Dans mon esprit, la clé est de découpler la gestion des messages avec le ruisseau de la mécanique, et si vous arrêter d'essayer de consommer le message comme un seul ReadBytes() à partir d'un flux, la vie devient beaucoup plus simple.
[tout cela est vrai si votre lit sont de blocage, ou asynchrone (APM/attendre)]
Je pense que
BufferedStream
est la solution au problème. Il est également possible d'aller non luslen
octet de données en appelant les Chercher.Croissante de la mémoire
Contrairement à
BufferedStream
où lasize
est spécifié initialement,MemoryStream
peut se développer.Se souvenir de flux de données en continu
MemoryStream
détient tous les dara-lire tout le temps, alors queBufferedStream
ne détient qu'un segment de flux de données.Cours d'eau de Source vs tableau d'octets
MemoryStream
permet d'ajouter des entrées-octets dansWrite()
méthode qui peut êtreRead()
à l'avenir. Alors queBufferedSteam
prend en entrée-octets à partir d'une autre source-flux spécifié dans le constructeur.Il semble que vous voulez lire à partir de la socket dans un MemoryStream de la mémoire tampon, puis " pop " des données de la mémoire tampon et de le remettre à chaque fois un certain octet est rencontré. Il ressemblerait à quelque chose comme ceci:
Vous pouvez le faire avec un
Stream
l'enveloppant d'unConcurrentQueue<ArraySegment<byte>>
(gardez à l'esprit ce fait en avant uniquement). Cependant, je n'aime vraiment pas l'idée de conserver les données en mémoire avant de faire quelque chose avec elle; il vous ouvre à tout un tas d'attaques (intentionnelle ou non) à propos de la taille du message. Vous pouvez également Google "tampon circulaire".En fait, vous devez écrire du code qui n'quelque chose de significatif avec les données dès qu'il est reçu: "Pousser l'Analyse" (c'est ce que, par exemple, SAXOPHONE prend en charge). Comme un exemple de la façon dont vous le faire avec du texte:
Si vous doit être en mesure d'accepter les messages dans leur intégralité avant de la désérialisation, vous pouvez utiliser un MemoryMappedFilequi a l'avantage de l'envoi de l'entité ne sera pas en mesure de out-of-mémoire de votre serveur. Ce qui est difficile est de réinitialiser le fichier de retour à zéro; car qui peut tas de questions. Une façon de lutter contre cela est de:
TCP Récepteur Fin
Désérialisation Fin
Le TCP récepteur fin est très simple. Le deserializer fin aurez besoin élémentaire de la mémoire tampon de couture logique (n'oubliez pas d'utiliser
Buffer.BlockCopy
et pasArray.Copy
).Note de côté: Sonne comme un projet amusant, si j'ai le temps et rappelez-vous que je puisse aller de l'avant et de mettre en œuvre ce système.
Il y a seulement trois réponses ici qui fournissent code.
L'un d'eux est maladroite et que les autres n'ont pas répondu à la question.
Ici une classe que vous pouvez simplement copier et coller: