TcpClient vs Socket en cas d’asynchronisme

Ce n’est pas encore un autre TcpClient vs Socket.

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 connecter, envoyer et recevoir des données de stream sur un réseau en mode de blocage synchrone.

Et pour la classe Socket:

La classe Socket vous permet d’effectuer un transfert de données synchrone et asynchrone à l’aide de l’un des protocoles de communication répertoriés dans l’énumération ProtocolType.

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

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

Tout d’abord, vous savez pourquoi la classe Socket dans .NET 4.5 n’implémente en aucune manière le modèle TAP, c’est-à-dire que ReadAsync et WriteAsync renvoient une tâche (événement s’il est appelé différemment pour préserver la compatibilité avec les versions antérieures)?

Quoi qu’il en soit, il est assez facile de construire une méthode Task à partir d’une paire de méthodes de modèle APM, alors appelons cette méthode asynchrone (pour la lecture) ReadAsyncTAP (retour d’une tâche).

D’accord ? Supposons maintenant que je souhaite coder une méthode client async Task ReadNbBytes(int nbBytes) que je vais appeler depuis mon code pour lire de manière asynchrone un certain nombre d’octets sur le réseau.

L’implémentation de cette méthode basée exclusivement sur TcpClient obtiendrait le NetworkStream en appelant GetStream et contiendrait une boucle asynchrone en attente d’un appel ReadAsync jusqu’à ce que la mémoire tampon soit saturée.

L’implémentation de cette méthode basée sur le socket contiendrait une boucle asynchrone en attente de ReadAsyncTAP jusqu’à saturation de la mémoire tampon.

En fin de compte, du sharepoint vue du code client, je suppose que cela ne fait aucune différence. Dans les deux cas, l’appel à await ReadNbBytes “retournera” immédiatement. Cependant, je suppose que cela fait une différence en coulisse … Pour le TcpClient, en s’appuyant sur NetworkStream, la lecture est-elle bloquée ou non, à aucun moment, par rapport à l’utilisation directe de socket? Si ce n’est pas le cas, la remarque faite pour le TcpClient est fausse lorsqu’on parle de mode de blocage synchrone

Serait grandement apprécié si quelqu’un pouvait clarifier!

Merci.

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

Stream types de Stream sont “intéressants”: par défaut, la classe de base Stream implémentera les E / S asynchrones en bloquant un thread de pool de threads sur les E / S synchrones. Ainsi, vous ne voudrez plus jamais faire d’E / S asynchrones sur un MemoryStream , qui ne fournit que des méthodes synchrones.

NetworkStream fournit des E / S asynchrones. Par conséquent, les E / S asynchrones sur les instances NetworkStream sont en réalité asynchrones. Mais ce n’est pas toujours le cas: FileStream en particulier n’est généralement pas asynchrone, mais c’est le cas si vous construisez l’instance juste .

Concernant la raison pour laquelle Socket n’a pas de méthodes TAP: c’est une très bonne question! Je pensais que c’était un oubli, mais maintenant que .NET 4.5 est disponible, il semble que cela ait été laissé de côté. Il se peut qu’ils ne veuillent tout simplement pas trop compliquer l’API – Socket a déjà deux API synchrones et asynchrones couvrant le même ensemble d’opérations ( Send , Send , SendTo , Receive , ReceiveFrom , Connect , Accept , Disconnect ). TAP nécessiterait à son tour deux API asynchrones supplémentaires pour cet ensemble complet. Cela créerait au moins une situation de dénomination intéressante (les *Async noms *Async sont déjà pris et ils appendaient deux noms supplémentaires *Async pour chaque opération).

Remarque secondaire: les API “supplémentaires” sont destinées aux communications Socket asynchrones hautes performances. Ils utilisent SocketAsyncEventArgs , qui n’est pas aussi facile à utiliser mais produit moins de déchets mémoire. Si des API TAP étaient ajoutées à Socket , elles souhaiteraient fournir à la fois les versions faciles à utiliser (wrapping Begin / End ) et les versions les plus performantes (wrapper Async ).

Si vous souhaitez créer des méthodes TAP pour Socket , les opérations en attente de socket de Stephen Toub constituent un bon sharepoint départ (il fournit uniquement des enveloppes pour l’API hautes performances). J’utilise quelque chose de similaire pour mes sockets async enabled.