receive - socket listener c#
TcpClient vs Socket cuando se trata de asincronÃa (1)
La E / S TcpClient
en las TcpClient
de TcpClient
no se bloquea. Parece que los documentos de MSDN están equivocados (puede verificar esto en Reflector siguiendo las llamadas de E / S asincrónicas de NetworkStream
).
Stream
tipos de Stream
son "interesantes": de forma predeterminada, la clase base de Stream
implementará E / S asíncronas al bloquear un hilo del grupo de subprocesos en E / S síncrona. Por lo tanto, nunca querrá hacer E / S asíncronas en algo como MemoryStream
, que solo proporciona métodos sincrónicos.
NetworkStream
proporciona E / S asíncronas, por lo que la E / S asincrónica en las instancias de NetworkStream
es realmente asincrónica. Pero este no es siempre el caso: FileStream
en particular no suele ser asíncrono, pero lo es si construye la instancia correcta .
En cuanto a por qué Socket
no tiene métodos TAP: ¡esa es una muy buena pregunta! Supuse que era un descuido, pero ahora que se lanzó .NET 4.5, parece que se dejó a propósito. Puede ser que simplemente no quieran complicar demasiado la API: Socket ya tiene API síncronas y dos asincrónicas que cubren el mismo conjunto de operaciones ( Send
, SendTo
, Receive
, ReceiveFrom
, Connect
, Accept
, Disconnect
). TAP a su vez requeriría dos API asíncronas adicionales para ese conjunto completo. Eso al menos causaría una situación de nomenclatura interesante (los nombres *Async
ya están tomados, y agregarían dos más *Async
nombres *Async
para cada operación).
Nota al margen: las API "adicionales" son para comunicación Socket
asíncrona de alto rendimiento. Usan SocketAsyncEventArgs
, que no es tan fácil de usar, pero produce menos basura en la memoria. Si las API de TAP se agregaron a Socket
, querrían ofrecer las versiones fáciles de usar (que envuelven Begin
/ End
) y las versiones de mayor rendimiento (que envuelven Async
).
Si eres interesante en la creación de métodos TAP para Socket
, un buen punto de partida son las operaciones de espera de socket de Stephen Toub (él solo proporciona envoltorios para la API de alto rendimiento). Utilizo algo similar para mis enchufes habilitados para asincronización.
Este no es otro TcpClient vs Socket.
TcpClient es un envoltorio alrededor de la clase Socket para facilitar el desarrollo, y también expone el socket subyacente.
todavía ...
En la página de biblioteca de MSDN para la clase TcpClient, se puede leer la siguiente observación:
La clase TcpClient proporciona métodos simples para conectar, enviar y recibir datos de transmisión a través de una red en modo de bloqueo síncrono.
Y para la clase Socket:
La clase Socket le permite realizar transferencias de datos síncronas y asíncronas utilizando cualquiera de los protocolos de comunicación enumerados en la enumeración ProtocolType.
Para enviar / recibir algunos datos de forma asincrónica solo a través del TcpCient, se debe realizar una llamada a GetStream para recuperar el NetworkStream subyacente de / sobre qué datos se pueden leer / escribir de forma asincrónica llamando a los métodos ReadAsync y WriteAsync, siguiendo el patrón TAP (potencialmente usando construcciones async / await).
Para enviar / recibir algunos datos de forma asincrónica a través del Socket (no soy experto pero creo que lo hice bien), podemos directamente leer / escribir desde / en la instancia del socket llamando a BeginRead / EndRead BeginWrite / EndWrite (o solo ReadAsync o WriteAsync ... no exponer el patrón TAP, es decir, no devolver una Tarea ... confuso).
Antes que nada, ¿alguna idea de por qué la clase Socket en .NET 4.5 no implementa de ninguna manera el patrón TAP, es decir, ReadAsync y WriteAsync Returning Task (evento si se llama de manera diferente para conservar la compatibilidad con versiones anteriores)?
De todos modos, es bastante fácil construir un método de Tarea desde el par de métodos de modelo de APM, así que digamos que llamo a este método asíncrono (para lectura) ReadAsyncTAP (devolviendo una Tarea).
De acuerdo ? Así que ahora digamos que quiero codificar un método de cliente async Task<Byte[]> ReadNbBytes(int nbBytes)
que llamaré desde mi código para leer asincrónicamente un cierto número de bytes de la red.
La implementación de este método basado exclusivamente en un TcpClient obtendría el NetworkStream llamando a GetStream y contendría un bucle asíncrono en espera de las llamadas de ReadAsync hasta que el búfer esté completo.
La implementación de este método basada en el Socket contendría un bucle asíncrono en espera en ReadAsyncTAP hasta que se llene el búfer.
Al final del día, desde el punto de vista del código del cliente, supongo que no importa. En ambos casos, la llamada para await ReadNbBytes
''volverá'' inmediatamente. Sin embargo, supongo que hace la diferencia entre bastidores ... Para el TcpClient, dependiendo de NetworkStream, ¿la lectura de alguna manera se bloquea o no en algún punto, en comparación con el uso directo del zócalo? Si no, ¿la observación hecha para el TcpClient es incorrecta cuando se habla de modo de bloqueo síncrono?
Sería muy apreciado si alguien pudiera aclarar!
Gracias.