wfc visual studio servicio publicar consumir consume c# wcf

c# - visual - ¿Manera eficiente de enviar imágenes a través de WCF?



wcf service (7)

  1. Su solución se ve bien para mí, pero sugiero (como otros lo hicieron) que use mosaicos y comprima el tráfico cuando sea posible. Además, creo que debería enviar toda la imagen de vez en cuando, solo para asegurarse de que los deltas del cliente tengan una "base" común.

  2. Quizás pueda usar una solución existente para transmisión, como RTP-H263 para transmisión de video. Funciona de maravilla, usa compresión y está bien documentado y ampliamente utilizado. A continuación, puede omitir la parte WCF e ir directamente a la parte de transmisión (ya sea a través de TCP o sobre UDP). Si su solución debe pasar a producción, tal vez el enfoque de transmisión H263 sería mejor en términos de capacidad de respuesta y uso de la red.

Estoy aprendiendo WCF, LINQ y algunas otras tecnologías al escribir, desde cero, una aplicación de control remoto personalizada como VNC. Lo estoy creando con tres objetivos principales en mente:

  1. El servidor proporcionará "control remoto" en un nivel de aplicación (es decir, ventanas integradas) en lugar de acceso completo al escritorio.
  2. El cliente puede seleccionar cualquier cantidad de aplicaciones que se ejecutan en el servidor y recibir una secuencia de imágenes de cada una de ellas.
  3. Un cliente puede conectarse a más de un servidor simultáneamente.

En este momento estoy usando WCF para enviar una matriz de bytes que representa la ventana que se envía:

using (var ms = new MemoryStream()) { window.GetBitmap().Save(ms, ImageFormat.Jpeg); frame.Snapshot = ms.ToArray(); }

Implementación de GetBitmap:

var wRectangle = GetRectangle(); var image = new Bitmap(wRectangle.Width, wRectangle.Height); var gfx = Graphics.FromImage(image); gfx.CopyFromScreen(wRectangle.Left, wRectangle.Top, 0, 0, wRectangle.Size, CopyPixelOperation.SourceCopy); return image;

Luego se envía a través del WCF (TCPBinding y siempre estará en la LAN) al cliente y se reconstruye en un formulario de Windows en blanco sin ningún borde como este:

using (var ms = new MemoryStream(_currentFrame.Snapshot)) { BackgroundImage = Image.FromStream(ms); }

Me gustaría que este proceso sea lo más eficiente posible tanto en el uso de la CPU como en el de la memoria, con el ancho de banda en tercer lugar. Mi objetivo es que el cliente se conecte a más de 5 servidores con más de 10 aplicaciones por servidor.

¿Es mi método actual el mejor enfoque (mientras sigo usando estas tecnologías) y hay algo que pueda hacer para mejorarlo?

Ideas que estoy buscando (pero no tengo experiencia con):

  • Usar una biblioteca de gráficos de código abierto para capturar y guardar las imágenes en lugar de la solución .Net.
  • Guardando como PNG u otro tipo de imagen en lugar de JPG.
  • Enviar deltas de imágenes en lugar de una imagen completa cada vez.
  • Intente y "grabe" las ventanas y cree una secuencia de video comprimido en lugar de instantáneas de imágenes (¿mpeg?).

Debe tener en cuenta estos puntos:

Justo después de pasar por todos estos pasos y estar satisfecho con su código final, puede descargar el código fuente de VncSharp . Implementa el protocolo RFB (entrada de Wikipedia) , "a simple protocol for remote access to graphical user interfaces. Because it works at the framebuffer level it is applicable to all windowing systems and applications, including X11, Windows and Macintosh. RFB is the protocol used in VNC (Virtual Network Computing)."


En lugar de capturar toda la imagen, solo envíe pequeñas subsecciones de la imagen. Significado: comenzando en la esquina superior izquierda, envíe una imagen de 10x10 píxeles, luego "mueva" diez píxeles y envíe el siguiente cuadro de 10 píxeles, y así sucesivamente. A continuación, puede enviar docenas de imágenes pequeñas y luego actualizar la imagen completa pintada en el cliente. Si ha usado RDC para ver imágenes en una máquina remota, probablemente lo haya visto hacer este tipo de pintura de pantalla.

Al usar las secciones de imagen más pequeñas, puede dividir también los deltas, de modo que si nada ha cambiado en la sección actual, puede omitirlo de manera segura, informar al cliente que se está salteando y luego pasar a la siguiente sección.

Definitivamente querrá usar compresión para enviar las imágenes. Sin embargo, debe verificar si obtiene tamaños de archivo más pequeños utilizando compresión similar a gZip, o si usa un códec de imagen que le brinda mejores resultados. Nunca he hecho una comparación, así que no puedo decirlo de una manera u otra.


La forma más rápida de enviar datos entre el cliente / servidor es enviar una matriz de bytes o varias matrices de bytes. De esta forma, WCF no tiene que hacer ninguna serialización personalizada en sus datos.

Eso dijo. Debe usar la nueva biblioteca WPF / .Net 3.5 para comprimir sus imágenes en lugar de las de System.Drawing. Las funciones en el espacio de nombres System.Windows.Media.Imaging son más rápidas que las anteriores y aún se pueden usar en winforms.

Para saber si la compresión es el camino a seguir, tendrá que comparar su escenario para saber cómo se compara el tiempo de compresión / descompresión con la transferencia de todos los bytes descomprimidos.

Si transfiere los datos a través de Internet, entonces la compresión ayudará con seguridad. Entre los componentes en la misma máquina o en una LAN, el beneficio puede no ser tan obvio.

También puedes intentar comprimir la imagen, luego dividir los datos y enviarlos de forma asíncrona con un ID de fragmento que puedes resolver juntos en el cliente. Las conexiones de Tcp comienzan lentamente y aumentan en ancho de banda con el tiempo, por lo que comenzar dos o cuatro al mismo tiempo debería reducir el tiempo total de transferencia (todo dependiendo de la cantidad de datos que está enviando). La fragmentación de los bytes de imágenes comprimidas también es más fácil en términos de lógica en comparación con hacer mosaicos en las imágenes reales.

En resumen : System.Windows.Media.Imaging debería ayudar tanto a la CPU como al ancho de banda en comparación con su código actual. En cuanto a la memoria, yo diría que es lo mismo.



Trabajé en un proyecto similar hace un tiempo. Este fue mi enfoque general:

  • Rasterizó el mapa de bits capturado en mosaicos de 32x32
  • Para determinar qué mosaicos habían cambiado entre marcos, utilicé el código no seguro para compararlos con 64 bits a la vez.
  • En el conjunto de teselas Delta, apliqué uno de los filtros PNG para mejorar la compresibilidad y obtuve los mejores resultados con el filtro Paeth
  • Utiliza DeflateStream para comprimir los deltas filtrados
  • Se BinaryMessageEncoding el enlace personalizado BinaryMessageEncoding al servicio para transmitir los datos en binario en lugar de la versión codificada en base64 predeterminada

Algunas consideraciones del lado del cliente. Cuando se trata de grandes cantidades de datos que se transfieren a través de un servicio WCF, descubrí que algunos parámetros de HttpTransportBinding y XmlDictionaryRenderQuotas se configuraron en valores bastante conservadores. Entonces querrás aumentarlos.


Bitmap scrImg = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); Graphics scr; scr.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.PrimaryScreen.Bounds.Size); testPictureBox.Image = (Image)scrImg;

Uso este código para capturar mi pantalla.