Haute performance asynchrone en attente de sockets
Je suis en train d'écrire une application qui nécessitera de faire des centaines de connexions socket tcp pour lire/écrire des données.
Je suis venu à travers cet extrait de code ici et je me demande comment je peux le rendre plus robuste.
Présentement, c'est comment je vais appeler le code:
foreach (var ip in listofIps)
{
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(ip), 4001);
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
client.Connect(remoteEP);
await ReadAsync(client);
}
- Il n'y a rien de mal avec le ci-dessus, et comment peut-il être optimisé tel qu'il fonctionne en même temps?
Dans l'extrait de code, la taille de la mémoire tampon est fixé à 1000. Tout comme une simple illustration, si je devais tenter d'imprimer uniquement les octets reçus, et pas le reste 0x00s, je dois faire quelque chose comme ceci:
while (true) { await s.ReceiveAsync(awaitable); int bytesRead = args.BytesTransferred; if (bytesRead <= 0) break; var hex = new StringBuilder(bytesRead * 2); var msg = new byte[bytesRead]; for (int i = 0; i < bytesRead; i++) msg[i] = args.Buffer[i]; foreach (byte b in msg) hex.AppendFormat("{0:x2} ", b); AppendLog(string.Format("RX: {0}", hex)); }
- Est-il un moyen plus efficace de faire cela? Auparavant, je voudrais réitérer la totalité de la mémoire tampon et d'imprimer les données, mais qui me donnera tout un tas de fuite 0x00s que mon protocole est n'importe où entre 60 à 70 octets de long.
Vous ne pouvez pas obtenir beaucoup de réponses à cette question car elle est trop large et vous vous demandez comme " peut-il être optimisé?'. La réponses est généralement un oui retentissant.
J'ai fait état les domaines que je voulais qu'il soit optimisé. Je ne pense pas que la question est plus large que vous le faire sonner. Je n'ai pas demandé "cela peut-il être optimisé?" en général
Mais vous demandé à trois ou quatre questions qui ne sont pas directement liées. Vous devriez vous poser une seule question à la fois.
Ce code est actuellement en attente de chaque tour - plutôt que de le faire simultanément. Est-ce vraiment votre intention?
Je vous remercie pour cette. Je veux qu'ils exécutent en même temps, comment le code devrait-il être?
J'ai fait état les domaines que je voulais qu'il soit optimisé. Je ne pense pas que la question est plus large que vous le faire sonner. Je n'ai pas demandé "cela peut-il être optimisé?" en général
Mais vous demandé à trois ou quatre questions qui ne sont pas directement liées. Vous devriez vous poser une seule question à la fois.
Ce code est actuellement en attente de chaque tour - plutôt que de le faire simultanément. Est-ce vraiment votre intention?
Je vous remercie pour cette. Je veux qu'ils exécutent en même temps, comment le code devrait-il être?
OriginalL'auteur Null Reference | 2013-06-13
Vous devez vous connecter pour publier un commentaire.
Vous n'avez pas besoin de "haute performance prises" pour que. Le code est beaucoup plus simple avec des régulière de la performance des sockets.
Pour commencer, ne pas utiliser la coutume awaitables à partir du lien que vous avez posté. Ils sont parfaitement bien pour certaines personnes (et complètement "robuste"), mais vous n'en avez pas besoin et votre code sera plus simple sans eux.
Oui. Vous ne devriez pas mélanger blocage (
Connect
) et asynchrone (ReadAsync
) du code. Je recommande quelque chose comme ceci:Où
ConnectTaskAsync
est un ROBINET standard-sur-APM wrapper:Marc Gravel a souligné, ce code (et votre code d'origine) est de connecter les prises une à une. Vous pouvez utiliser
Task.WhenAll
pour se connecter simultanément.Tout d'abord, vous devez définir un ROBINET-sur-APM
ReceiveTaskAsync
wrapper similaire à ci-dessus. Lorsque vous traitez avec des données binaires, j'aime aussi avoir une méthode d'extension sur des tableaux d'octets pour le dumping:Alors vous pouvez avoir un code comme ceci:
Si vous faites beaucoup de binaire de manipulation, vous pouvez trouver mon ArraySegments bibliothèque utile.
Oh, c'est plus complexe que cela. 🙂 Les Sockets sont un flux abstraction, pas un message l'abstraction. Donc, si vous voulez définir des "messages" dans votre protocole, vous devez inclure un préfixe de longueur ou un délimiteur octet de sorte que vous pouvez détecter les limites de message. Ensuite, vous devez écrire le code qui va analyser vos messages, en gardant à l'esprit que les blocs de données lues à partir de la prise peut contenir qu'une partie du message (si vous avez de la mémoire tampon), un message complet, plusieurs messages complets, et peut également mettre fin à une partie d'un message (encore une fois, de mise en mémoire tampon). Et vous devez également tenir compte de votre existant de la mémoire tampon lors de la réception du nouveau bloc.
J'ai un TCP/IP .NET Sockets FAQ sur mon blog qui cela concerne en particulier les adresses et a quelques exemple de code à l'aide de mon personnel de préférences par défaut pour les messages d'encadrement (4 octets de poids faible longueur de préfixe).
Que l'on est étonnamment délicat:
SendTaskAsync()
doit retournerTask<int>
, pas seulementint
. 2. Pourquoi êtes-vous boxe0
commestate
? Je pense quenull
a plus de sens. 3. Ne serait-il pas plus logique d'utiliser lebyte[], int, int
surcharge au lieu de laIList<ArraySengment<byte>>
surcharge?Merci pour les corrections. Mis à jour. "0" est une fâcheuse habitude que j'ai depuis que j'ai fait beaucoup de programmation intégré dans C au cours des 18 derniers mois et il n'est pas "null" dans C. j'ai utilisé le
ArraySegment
surcharge je ne voudrais pas avoir à copier des tableaux autour si l'écriture que partiellement suis passé par (rare mais possible).Avec les autres surcharge, vous n'auriez toujours pas à copier quoi que ce soit, vous serait-il suffit d'appeler la méthode avec d'autres
offset
. Et vous n'auriez pas à créer l'unique élément de tableau.Bon point. Mis à jour à nouveau. Trop de surcharges! 🙂
ConnectTaskAsync
est pas défini...OriginalL'auteur Stephen Cleary