2010-02-18 27 views
9

Cuando llamo a BeginSend en un socket, paso un delegado que se llamará (por un hilo diferente) cuando se hayan enviado los datos.¿Cuántas solicitudes de socket asíncronas pueden estar pasando en el mismo socket?

¿Qué pasaría si llamo a BeginSend en otro momento mientras que el primero aún no ha sido 'devuelto?'

¿Cuál es el comportamiento correcto para enviar datos? do BeginSend, y en la devolución de llamada, ¿EndSend e inicia otro envío? ¿O es realmente inteligente tener múltiples BeginSends trabajando al mismo tiempo?

esta es la página BeginSend en MSDN que no da una respuesta a esta pregunta: BeginSend msdn

Respuesta

16

As O.K.W. dice, múltiples llamadas pendientes BeginSend funcionarán bien. Sin embargo, probablemente DEBES tener en cuenta algunas cosas.

En primer lugar, si se trata de un socket TCP, esta sigue siendo una única secuencia de datos de igual a igual.

En segundo lugar si todas las llamadas BeginSend se producen en el mismo hilo, el resultado será que el par recibe los datos en el orden de las llamadas. Si sus llamadas BeginSend se producen a partir de diferentes hilos, entonces los datos podrían llegar en cualquier orden, ya que es probable que exista una condición de carrera entre cada uno de los envíos. Esto puede o no tener importancia para usted (depende de si está enviando mensajes discretos y completos con cada envío o no).

En tercer lugar, si usa TCP y envía más rápido de lo que puede recibir el código en el otro extremo del socket, entonces puede llenar la ventana TCP y las pilas TCP comenzarán a realizar control de flujo en su flujo de datos. Si continúa emitiendo llamadas BeginSend, PUEDE terminar en una situación en la que las devoluciones de llamada tardan más y más en llamarse, ya que la pila TCP en su servidor pone en cola los datos para enviar (solo recibe la devolución una vez que los datos han sido enviados y El control de flujo basado en la ventana TCP evitará que se envíen nuevos datos hasta que la ventana TCP ya no esté "llena", es decir, que el par haya enviado ACK para algunos de los datos que son in flight).

Puede entrar en una situación en la que esté agotando recursos en la máquina de envío de manera incontrolable (emite un BeginSend y no tiene idea de cuándo se completará y cada envío utiliza memoria para el búfer que se envía y potencialmente non-paged pool abajo en el código de Winsock ... Non-paged pool es un recurso de todo el sistema y es bastante escaso en sistemas operativos anteriores a Vista y algunos controladores de mal comportamiento pueden mostrar la casilla azul si non-paged pool está bajo o agotado. Además, puede estar bloqueando páginas de memoria en la memoria y hay otro límite amplio del sistema en el número de páginas de memoria bloqueadas.

Debido a estos problemas, generalmente es mejor implementar su propio flujo de nivel de protocolo control que limita el número de llamadas BeginSend que pueden estar pendientes en cualquier momento (utilizando un nivel de protocolo ACK, tal vez) o para trabajar con el control de flujo de la ventana TCP y usar la finalización de un envío pendiente para emitir un nuevo envío y puede Ponga los datos en cola para enviar en su propia memoria y tenga un control total sobre los recursos utilizados y lo que hace si pone en cola "demasiados" datos. Ver mi blog aquí para obtener más detalles sobre esto: http://www.serverframework.com/asynchronousevents/2011/06/tcp-flow-control-and-asynchronous-writes.html

Ver esta respuesta: what happens when tcp/udp server is publishing faster than client is consuming? para obtener más información sobre el control de flujo de ventana TCP y lo que sucede con los que superpuesto de E/S (en C++ tierra) cuando usted lo ignora y emisión demasiados envíos superpuestos ...

En resumen, la publicación de múltiples llamadas simultáneas BeginSend es la forma óptima de flujo de datos TCP, pero debe asegurarse de no enviar "demasiado rápido" ya que una vez que consume recursos en un manera que no puede controlar y que es potencialmente fatal para la máquina en la que se está ejecutando su código. Por lo tanto, no permita que haya un número ilimitado de llamadas BeginSend sobresalientes e, idealmente, perfile la casilla para asegurarse de no estar agotando los recursos de todo el sistema.

+1

@Lens, esa es una buena +1 –

+0

@lens: Tengo ventanas incorporadas en el protocolo que estoy enviando (smpp) para que nunca sean una cuestión de enviar demasiado rápido. Sin embargo, el punto fuera de orden que menciones sería un problema. – Toad

+0

@Len, mal escrito su nombre en mi comentario anterior, mi disculpa :) –

4

basé lo que read here, parece como tener múltiples concurrentes BeginSend es factible.

Extracto:

  1. Puede poner en cola múltiples BeginSends al mismo tiempo. No necesita cerradura
  2. Si no crea un método de devolución de llamada, ¿cómo sabe si el envío es exitoso? Es posible que desee ignorar el éxito, más como un método de detección de incendio y olvidar, pero al menos necesita saber cuándo es seguro finalizar su programa.
  3. La otra cosa que puede hacer es usar el IAsyncResult que obtiene de BeginSend. Puede usar WaitHandle para esperar a que se complete la operación. Pero eso derrota el propósito total de usando Async en primer lugar.
  4. Mi recomendación es utilizar una devolución de llamada, y asegúrese de llamar al y el número de bytes que ha enviado realmente se envía y terminan con agrado la operación de envío.

Actualización:
Probamos simultánea BeginSend basado en la codes on MSDN y los datos se envían sin excepción. Sin embargo, tenga en cuenta que la conexión para el mismo socket debe abrirse antes. El BeginConnect simultáneo no funcionará.

+0

¿Esto multiplexa múltiples flujos de datos independientes en un solo socket? ¿Es la respuesta de Microsoft a SCTP? –

+0

interesante. Pero, ¿es más rápido que solo enviar paquetes por paquete con solo un BeginSend pendiente? Pregunto esto porque estoy haciendo un servidor que debería tener un buen rendimiento, y podría ser que uno tenga al menos X pendiente de BeginSends para tener un rendimiento decente. En este momento, no sabría – Toad

+0

Robert - No, en absoluto. Si el socket es un socket TCP, entonces tiene una sola transmisión. La emisión de múltiples llamadas a 'BeginSend' simplemente le permite poner múltiples escrituras en cola de forma asíncrona. –