【问题标题】:Efficient way to send images via WCF?通过 WCF 发送图像的有效方法?
【发布时间】:2009-12-01 22:05:36
【问题描述】:

我正在通过从头开始编写自定义远程控制应用程序(如 VNC)来学习 WCF、LINQ 和其他一些技术。我在创建它时考虑了三个主要目标:

  1. 服务器将在应用程序级别(即无缝窗口)提供“远程控制”,而不是完整的桌面访问。
  2. 客户端可以选择服务器上运行的任意数量的应用程序并接收每个应用程序的图像流。
  3. 一个客户端可以同时连接到多个服务器。

现在我正在使用 WCF 发送代表正在发送的窗口的字节数组:

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

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;

然后通过 WCF(TCPBinding,它将始终通过 LAN)发送到客户端,并以没有边框的空白窗口形式重建,如下所示:

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

我想让这个过程在 CPU 和内存使用方面尽可能高效,带宽排在第三位。我的目标是让客户端连接到 5 台以上的服务器,每台服务器有 10 多个应用程序。

我现有的方法是最好的方法(同时继续使用这些技术)吗?我可以做些什么来改进它?

我正在研究的想法(但我没有经验):

  • 使用开源图形库而不是 .Net 解决方案来捕获和保存图像。
  • 另存为 PNG 或其他图像类型,而不是 JPG。
  • 每次都发送图像增量而不是完整图像。
  • 尝试“记录”窗口并创建压缩视频流,而不是图片快照(mpeg?)。

【问题讨论】:

    标签: c# wcf


    【解决方案1】:

    您应该注意以下几点:

    只需通过所有这些步骤并对最终代码感到满意,您就可以下载VncSharp source code。它实现了the RFB Protocol(Wikipedia entry)"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)."

    【讨论】:

      【解决方案2】:

      不久前我从事过一个类似的项目。这是我的一般做法:

      • 将捕获的位图光栅化为 32x32 的图块
      • 为了确定哪些图块在帧之间发生了变化,我使用了不安全的代码来一次比较它们 64 位
      • 在一组增量图块上,我应用了一个 PNG 过滤器来提高可压缩性,并使用 Paeth filter 获得了最佳效果
      • 使用DeflateStream 压缩过滤后的增量
      • 使用 BinaryMessageEncoding 自定义绑定到服务以二进制而不是默认的 Base64 编码版本传输数据

      一些客户端注意事项。在处理通过 WCF 服务传输的大量数据时,我发现 HttpTransportBindingXmlDictionaryRenderQuotas 的一些参数设置为相当保守的值。所以你会想要增加它们。

      【讨论】:

      • “在一组增量图块上,我应用了一个 PNG 过滤器来提高可压缩性,并使用 Paeth 过滤器获得了最佳效果”我想知道如何在 C# 中实现这一点,因为我没有看到在哪里应用这样的过滤器,并且 EncoderParameters 不接受任何类型的任何提示?
      【解决方案3】:

      看看这个:Large Data and Streaming (WCF)

      【讨论】:

      • 在此处提问之前,我已经阅读了 msdn 上的那部分内容......我非常想了解我的方法应该改变什么以及为什么。
      【解决方案4】:

      在客户端/服务器之间发送数据最快的方法是发送一个字节数组,或者几个字节数组。这样,WCF 就不必对您的数据进行任何自定义序列化。

      就是这么说的。您应该使用新的 WPF/.Net 3.5 库来压缩图像,而不是使用 System.Drawing 中的图像。 System.Windows.Media.Imaging 命名空间中的函数比旧的更快,并且仍然可以在 winforms 中使用。

      为了了解压缩是否是可行的方法,您必须对您的场景进行基准测试,以了解压缩/解压缩时间与传输所有未压缩字节的比较。

      如果您通过互联网传输数据,那么压缩肯定会有所帮助。在同一台机器或 LAN 上的组件之间,好处可能不那么明显。

      您也可以尝试压缩图像,然后将数据分块并使用您在客户端上拼凑的块 id 异步发送。 Tcp 连接开始缓慢并且带宽随着时间的推移而增加,因此同时启动两个或四个应该会减少总传输时间(这一切都取决于您发送的数据量)。与在实际图像中进行切片相比,将压缩图像字节分块也更容易逻辑。

      总结:与您当前的代码相比,System.Windows.Media.Imaging 应该对您的 CPU 和带宽都有帮助。记忆方面我猜差不多。

      【讨论】:

        【解决方案5】:

        只需发送图像的较小部分,而不是捕获整个图像。含义:从左上角开始,发送一个 10x10 像素的图像,然后“移动”十个像素并发送下一个 10px 的正方形,以此类推。然后您可以发送几十个小图像,然后在客户端更新绘制的完整图像。如果您使用 RDC 在远程计算机上查看图像,您可能已经看到它执行这种屏幕绘画。

        使用较小的图像部分,您也可以拆分增量,因此如果当前部分没有任何变化,您可以安全地跳过它,通知客户您正在跳过它,然后进入下一个部分.

        您肯定希望使用压缩来发送图像。但是,您应该检查是否通过使用类似于 gZip 的压缩来获得更小的文件大小,或者使用图像编解码器是否可以提供更好的结果。我从来没有进行过比较,所以我不能肯定地说。

        【讨论】:

        • 是的,我觉得将图像分割成瓦片并检测瓦片自上一帧以来是否发生变化绝对是我需要实现的优化。我认为最有效的方法是首先让整个图像上的一切工作尽可能好(获得正确的压缩,检测图像自上一帧以来是否发生变化,使用最快的方法序列化图像等)然后拆分图像并将所有改进应用于每个图块。
        • 我将检查各种图像格式与通用压缩的大小差异,但我非常有信心,要使压缩真正有效,它需要特定于上下文。我认为 jpg 和 png 会产生比使用 ​​bzip 或 gzip 压缩的 bmp 更小的图像尺寸。
        【解决方案6】:
        1. 您的解决方案对我来说看起来不错,但我建议(与其他人一样)您使用磁贴并尽可能压缩流量。此外,我认为您应该每隔一段时间发送一次整个图像,以确保客户端的增量具有共同的“基础”。

        2. 也许您可以使用现有的流媒体解决方案,例如用于视频流的 RTP-H263。它工作得很好,它使用压缩,并且有据可查并被广泛使用。然后,您可以跳过 WCF 部分并直接进入流部分(通过 TCP 或通过 UDP)。如果您的解决方案应该投入生产,也许 H263 流式处理方法在响应能力和网络使用方面会更好。

        【讨论】:

          【解决方案7】:
          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;
          

          我使用此代码来捕获我的屏幕。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-02-21
            • 1970-01-01
            • 2012-05-26
            • 1970-01-01
            • 1970-01-01
            • 2010-11-04
            • 2020-09-29
            • 2021-09-14
            相关资源
            最近更新 更多