TcpClient vs Socket lorsqu'il s'agit de asynchronousy

Ce N'est pas encore un autre Socket TcpClient vs.

TcpClient est un wrapper autour de la classe Socket pour faciliter le développement, exposant également le Socket sous-jacent.

Encore ...

Sur la page de la bibliothèque MSDN pour la classe TcpClient, on peut lire la remarque suivante:

La classe TcpClient fournit des méthodes simples pour la connexion, l'envoi, et recevoir des données de flux sur un réseau en mode de blocage synchrone.

Et pour la classe Socket :

La classe Socket vous permet d'effectuer à la fois synchrone et transfert de données asynchrone à l'aide de l'un des protocoles de communication listé dans L'énumération ProtocolType.

Pour envoyer / recevoir des données de manière asynchrone via le TcpCient uniquement, un appel à GetStream doit être effectué, pour récupérer le NetworkStream sous-jacent à partir de/sur lequel les données peuvent être lues/écrites de manière asynchrone en appelant les méthodes ReadAsync et WriteAsync, en suivant le modèle TAP (potentiellement en utilisant les constructions async/await).

Pour envoyer / recevoir des données de manière asynchrone via le Socket (Je ne suis pas expert mais je pense que j'ai bien compris), nous pouvons directement lire / écrire depuis / sur l'instance de socket elle-même en appelant BeginRead / EndRead BeginWrite / EndWrite (ou simplement ReadAsync ou WriteAsync .. ne pas exposer le modèle de TAP-c'est-à-dire ne pas renvoyer une tâche .. déroutant).

Tout d'abord, une idée de pourquoi la classe Socket dans. Net 4.5 n'implémente en aucune façon le modèle TAP, c'est-à-dire ReadAsync et WriteAsync retournant la tâche (événement s'il est appelé différemment pour préserver la compatibilité arrière)?

Quoi qu'il en soit, assez facile de construire une méthode de tâche à partir D'une paire de méthodes de modèle APM, disons que j'appelle cette méthode asynchrone (pour lire) ReadAsyncTAP (renvoyer une tâche).

Ok ? Alors maintenant, disons que je veux coder une méthode client async Task<Byte[]> ReadNbBytes(int nbBytes) que je vais appeler à partir de mon code pour lire de manière asynchrone un certain nombre d'octets du réseau.

La mise en œuvre de cette méthode basée exclusivement sur un TcpClient obtiendrait le NetworkStream en appelant GetStream et contiendra une boucle asynchrone en attente sur les appels ReadAsync jusqu'à ce que le tampon soit plein.

L'implémentation de cette méthode basée sur le Socket contiendrait une boucle asynchrone en attente sur ReadAsyncTAP jusqu'à ce que le tampon soit plein.

En fin de compte, du point de vue du code client, je suppose que cela ne fait aucune différence. Dans les deux cas, l'appel à await ReadNbBytes sera 'return' immédiatement. Cependant, je suppose que cela fait une différence derrière les coulisses ... Pour le TcpClient, en s'appuyant sur NetworkStream, la lecture bloque-t-elle ou non à tout moment, par rapport à l'utilisation directe du socket ? Si non est la remarque faite pour le TcpClient est FAUX Quand on parle de mode de blocage synchrone ?

Serait grandement apprecited si quelqu'un pouvait clarifier !

Merci.

21
demandé sur darkey 2012-08-16 09:21:13

1 réponses

Les E/S asynchrones sur les flux TcpClient ne bloquent pas. Il semble que les documents MSDN soient erronés (vous pouvez le vérifier dans Reflector en suivant les appels d'E/S asynchrones de NetworkStream).

Stream les types sont "intéressants": par défaut, la classe de base Stream implémentera des E/S asynchrones en bloquant un thread de pool de threads sur les E/S synchrones.

NetworkStream est-ce que fournir les E/S asynchrones, donc les E/S asynchrones sur les instances NetworkStream sont en fait asynchrones. Mais ce n'est pas toujours le cas: FileStream, en particulier, est généralement pas asynchrone, mais il est si vous construisez l'exemple juste à droite.

En ce qui concerne pourquoi Socket n'a pas de méthodes TAP: c'est une très bonne question! J'ai supposé que c'était un oubli, mais maintenant que. Net 4.5 est publié, il semble qu'il ait été laissé de côté exprès. Il se pourrait qu'ils ne veulent tout simplement pas compliquer le API Socket a déjà synchrone et deux Api asynchrones couvrant le même ensemble d'opérations (Send, SendTo, Receive, ReceiveFrom, Connect, Accept, Disconnect). TAP nécessiterait à son tour deux API asynchrones supplémentaires pour cet ensemble complet. Cela causerait au moins une situation de nommage intéressante (les noms *Async sont déjà pris, et ils ajouteraient deux autres noms *Async pour chaque opération).

Note latérale: les API "supplémentaires" sont pour les Socket communication. Ils utilisent SocketAsyncEventArgs, ce qui n'est pas aussi facile à utiliser mais produit moins de déchets de mémoire. Si les API TAP étaient ajoutées à Socket, elles souhaiteraient fournir les deux versions faciles à utiliser (wrapping Begin/End) et les versions plus performantes (wrapping Async).

Si vous êtes intéressant de créer des méthodes TAP pour Socket, un bon point de départ est le de Stephen Toub en attente des opérations de Socket (Il ne fournit que des wrappers pour L'API haute performance). J'utilise quelque chose de similaire pour mes prises async activées.

23
répondu Stephen Cleary 2015-06-10 22:14:05