You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SignalR位图远程桌面公网卡顿优化及base64替代方案咨询

公网卡顿核心原因
  • base64编码会把二进制数据体积膨胀33%,公网带宽有限的情况下传输开销直接上涨1/3
  • 当前用的PNG编码即使压到最低质量,对桌面这类静态内容多的场景压缩效率远低于视频编码,单帧体积仍然过大
  • 逐帧全量传输,没有做差帧优化,每次都传整个屏幕的内容,公网延迟高的情况下很容易出现帧堆积
  • 手动调用GC.Collect()会带来不必要的性能损耗,桌面端截图线程容易出现延迟波动
  • SignalR默认消息大小限制、公网传输丢包重传的叠加效应会进一步放大卡顿
针对性优化方案

一、传输层优化(优先落地,可直接解决80%问题)

首先移除base64编码,SignalR原生支持二进制消息传输,直接把二进制数组发出去即可,无需转base64,可直接减少33%的传输体积,修改代码如下:

  1. 桌面端修改
await _hubConnection.StartAsync();
var thread = new Thread(async () =>
{
    while (true)
    {
        Thread.Sleep(1);
        Rectangle bound = Screen.PrimaryScreen.Bounds;
        ImageCodecInfo pngEncoder = GetEncoder(ImageFormat.Png);
        System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
        EncoderParameters myEncoderParameters = new EncoderParameters(1);

        EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 0L);
        myEncoderParameters.Param[0] = myEncoderParameter;
        Bitmap screenshot = new Bitmap(bound.Width, bound.Height, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
        Graphics graphics = Graphics.FromImage(screenshot);
        graphics.CopyFromScreen(bound.X, bound.Y, 0, 0, bound.Size, CopyPixelOperation.SourceErase);

        using (var ms = new MemoryStream())
        {
            screenshot.Save(ms, pngEncoder, myEncoderParameters);
            // 直接传输二进制数组,删除base64转换逻辑
            await _hubConnection.InvokeAsync("Image", ms.ToArray());
        }
        Thread.Sleep(150);
        // 删掉手动GC触发逻辑,GC自动回收性能远高于手动调用
    }
});
thread.Start();
thread.Join();
  1. Hub端修改
public async Task Image(byte[] imgData)
{
    await Clients.All.SendAsync("ViewImage", imgData);
}

同时调整SignalR消息大小限制,在Program.cs中添加配置:

builder.Services.AddSignalR(options =>
{
    // 调整单条消息最大体积为10M,适配大帧传输
    options.MaximumReceiveMessageSize = 10 * 1024 * 1024;
})
// 开启MessagePack二进制序列化,比JSON序列化体积更小、速度更快
.AddMessagePackProtocol();
  1. 前端修改
<div class="text-center">
   <canvas id="received" width="1200" height="800" style="border: solid 1px black"></canvas>
</div>

<script>
connection.on("ViewImage", function (imgData) {
    var canvas = document.getElementById('received');
    var ctx = canvas.getContext('2d');
    // 二进制转Blob生成临时URL,性能远高于base64的dataurl
    let blob = new Blob([imgData], {type: 'image/png'});
    let source = URL.createObjectURL(blob);
    var img = new Image();
    img.src = source;
    img.onload = function ()
    {
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
        // 用完释放临时URL,避免内存泄漏
        URL.revokeObjectURL(source);
    }
});
</script>

二、编码层优化

  • 把PNG替换成WebP编码,相同画质下WebP体积比PNG小25%-50%,C#端可通过ImageSharp库实现WebP编码,前端原生支持WebP解码
  • 如果卡顿仍然明显,可改用视频编码方案:桌面端把多帧编码成H.264裸流,发送完关键帧之后只传增量帧,公网传输体积可以降到PNG的1/10以下,前端用MediaSource Extensions解码播放,帧率可稳定在30帧以上

三、内容逻辑优化

  • 增加差帧计算逻辑:只有屏幕内容变化的区域才编码传输,静态桌面场景下可把单帧体积降到原来的10%以内
  • 增加帧率动态调整逻辑:检测到公网延迟升高时,自动降低截图帧率或者编码质量,避免帧堆积导致的画面冻结

四、更高性能的替代方案

如果上述优化仍然达不到要求,可改用WebRTC做点对点流传输,只需要用SignalR做信令传输,流数据直接走UDP点对点传输,不需要通过服务器中转,公网延迟可降到100ms以内,抗丢包能力远高于TCP传输的SignalR,不会因为丢包出现卡顿冻结,非常适合远程桌面这类低延迟要求的场景。

内容的提问来源于stack exchange,提问作者Cəfərov Murad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 06:45:04