Sunshine 和 Moonlight 实现低延迟电脑无线投屏到电视
本文由 简悦 SimpRead 转码, 原文地址 zhuanlan.zhihu.com
背景
前两年买了一台 PC 放在书房来办公和玩游戏,最初还仅限于坐在电脑前对着显示器使用,后来开始琢磨是否有办法把画面投屏到客厅的电视上,能享受更大的画面尺寸。另外随着生活中的种种变故,能长时间坐在书房的机会逐渐减少,因此在家里任意地方,乃至出门的时候也能用各种设备连接 PC 的需求越发旺盛。普通的远程连接通过各类远程桌面软件就可以办到,但是如果需要玩游戏和看视频,那普通远程桌面的帧率不能满足需求,需要更加低延迟的方案。
经过种种尝试,目前使用的是 Sunshine + Moonlight 的串流解决方案,整体比较稳定,期间有了不少心得,在这里记录一下,全是干货,也算是最新的第一手资料,方便后人。
方案优点:
- 低延迟,更加适合看视频和玩游戏
- 最高可以支持 4k + 120Hz + HDR 的画质
- 服务端支持各种主流 PC 硬件
- 客户端支持各种设备
方案缺点:
- 因为定位是串流工具,所以缺乏远程桌面软件的各种便捷功能,例如傻瓜式地跨机器复制粘贴文本 / 文件
- 如果想实现出门的时候通过外网远程连接家里的电脑,对计算机网络知识和动手能力的要求较高,对计算机和电子设备小白并不友好
注意:本文记录的主要是整体方案,以及针对实践过程中遇到的各种问题的解决思路,具体实践中由于各人使用环境不尽相同,需要自行排查问题。
使用场景
通过各种设备连接家里的主力 PC 来远程办公或者玩游戏,包括:
- 躺在床上用手机或者平板操作 PC
- 不用把电脑搬到电视旁边,就能用电视的大屏幕观看电脑画面(例如玩游戏,看视频网站)
- 外出时使用笔记本电脑连接家里的 PC
我的软硬件环境:
PC 端:Windows 11, Nvidia 显卡
客户端:各种都有,包括 Windows 笔记本电脑, Macbook, 苹果手机 / 平板,安卓手机 / 平板 / 电视
原理
简单来说就是通过安装在电脑上的串流软件服务端将电脑屏幕画面实时发送到安装了串流软件客户端的设备上,本质上属于投屏,但是客户端同时可以通过键盘 / 鼠标 / 手柄等设备给服务端发送输入指令。为了能够高效地传输画面,需要借助电脑显卡对传输画面进行实时编码,并由客户端设备的硬件实时解码。
硬件要求:PC 服务端需要有独立显卡,集成显卡是否可以用没有实际测试过,估计比较吃力,意义不大。客户端需要有硬件解码的能力,最好可以支持 HEVC(也即 H265)的硬解(只要不是太旧的设备,都能支持)。
服务端软件:Sunshine,支持各种主流的 PC 操作系统和显卡(包括 Nvidia/AMD/Intel),适用于局域网和外网的串流场合。Nvidia 有一个 GeForceExperience 软件虽然也可以支持串流,但是仅支持自家显卡,而且官方也不再继续开发维护串流功能,因此还是推荐 Sunshine。
客户端软件:Moonlight,支持各种主流的 PC 和移动端操作系统,可以安装在 PC / 手机 / 平板 / 智能电视上面。
安装
Sunshine
首先通过下面的链接在 PC 上安装 Sunshine(打不开 github 的话自行百度),注意选择 latest 版本,不要使用 pre-release 版本,windows 电脑的话选择 sunshine-windows-installer.exe,推荐勾选开机自动启动。注意 Sunshine 必须要以 windows 服务的形式启动,不能直接去安装目录里点击 sunshine.exe 文件。所以启动 Sunshine 要么通过开机自动启动,要么点击开始菜单里的 Sunshine 快捷方式。
https://github.com/LizardByte/Sunshine/releases
Sunshine 的管理界面是网页形式,第一次进入的时候浏览器会警告非私密链接,选择忽略警告,继续访问。随后设置管理员用户名和密码,这个用户名密码是存储在本地的,必须牢记,如果忘了没办法找回,也就没法进入配置页面,但是不影响 Sunshine 服务的运行。
如果需要调整网页语言,去 Configuration 下面的 General 页面,在 Locale 里选择简体中文,点击 Save 和 Apply,网页会重启。
这样基本的安装就结束了,其他配置项自行摸索,一般不怎么需要改。
游戏管理
Sunshine 自带了基本的程序管理功能,在网页的 Applications 里面可以配置希望远程启动的各个程序的名称和执行路径,配合客户端使用。对于更复杂的游戏管理能力,Sunshine 也自带了电脑桌面以及 Steam 启动器。
总的来说 Sunshine 自带的程序管理功能比较简陋,而且启动有些游戏会失败。如果需要更成熟的游戏管理平台,这里推荐一款叫 Playnite 的游戏管理软件,支持多个游戏平台的资料导入,自动下载游戏封面图片,也提供大屏模式,方便投屏到电视上用手柄操作。可以在 Sunshine 里配置启动 Playnite,再从 Playnite 统一启动游戏。
Playnite - video game library manager
Moonlight
客户端支持各种操作系统和设备,去以下链接下载。
其中 iOS 设备直接去苹果 App Store 搜索安装,Android 设备会被指向 Google Play 商店,国内无法访问,可以从以下链接下载 apk 安装包。
Releases · moonlight-stream/moonlight-android · GitHub
各个客户端的界面基本一样,如果客户端和 Sunshine 在同一个局域网内,则会自动搜索到服务端的机器,第一次连接的时候需要在服务端的 Sunshine 管理页面的 PIN 页面中输入 pin 码,与客户端进行配对。之后在客户端里设置串流的分辨率和帧数,就可以开始串流了。如果有其它需求,自行摸索配置,其中安卓客户端的配置选项最丰富。
建议客户端配对的时候与服务端在同一个局域网内,方便操作。尤其是 iOS 设备受到苹果的安全限制,仅能在局域网内配对。
虚拟键盘
对于 iOS/Android 设备,在串流的时候可以采用三个手指同时点击屏幕的手势,唤起设备自带的虚拟键盘。许多安卓设备的厂商带有自己的手势系统,导致这个虚拟键盘的手势失效,需要用户自行排查解决(例如关闭安卓厂商的手势功能,或者有些设备可以开启游戏模式)。
常用快捷键
在电脑上使用 Moonlight 的时候,有一些常用的快捷键:
- Ctrl+Alt+Shift+Q - 退出串流,但是串流时启动的程序还在运行,需要在客户端里手动关闭
- Ctrl+Alt+Shift+X - 客户端切换窗口 / 全屏模式
- Ctrl+Alt+Shift+S - 实时显示串流状态,包括网络延迟、解码信息 (不支持 Steam Link 或者 Raspberry Pi)
- Ctrl+Alt+Shift+D - 最小化客户端窗口
完整文档见下。
Setup Guide · moonlight-stream/moonlight-docs Wiki · GitHub
网络连接
网络质量分为网络带宽 / 平均延迟 / 网络抖动几个因素,带宽决定了画质的上限,平均延迟决定了用户输入的响应速度,网络抖动决定了音画卡顿出现的几率。
网络带宽
各种常用画质所需的网络带宽:
720p 60Hz: 10Mb/s
1080p 60Hz: 20Mb/s
1080p 120Hz: 30Mb/s
2k 60Hz: 40Mb/s
2k 120Hz: 60Mb/s
4k 60Hz: 80Mb/s
4k 120Hz: 115Mb/s
内网环境下网络带宽往往不是问题,主要看客户端设备支持什么画质。如果客户端支持的帧率高于服务端所连接的显示器,可以在游戏里关闭垂直同步,解除帧率上限,或者使用后面介绍的虚拟屏幕。
外网环境下网络带宽取决于服务端的上行带宽,国内普通家庭宽带的上行带宽比较有限,哪怕是千兆宽带,电信 / 联通的上行带宽往往也只有 60Mb/s。相比之下,移动宽带的上行带宽给得大方一些,可能超过 100Mb/s。具体上行带宽有多少可以自行测速,往往不会超过 40Mb/s。因此外网环境下,更常用的是 1080p 60Hz 的画质,这个画质对于移动设备来说也足够了。
网络延迟
内网环境下网络延迟很低,如果服务端和客户端都是有线连接,那延迟能够稳定低于 1ms。使用 5GHz wifi 的话,信号非常好的情况下延迟大约在 5ms 左右。
外网环境下网络延迟很容易受各种因素影响,根据经验,同城延迟大约在 10ms,跨城延迟取决于地理距离 / 是否跨省 / 是否跨网络运营商,延迟从 15ms(相距 300 公里时实测)到上百 ms 不等。跨省、尤其是跨网络运营商的时候,有可能因为串流流量较高,或者因为处于网络高峰期而被限流。被限流时可能网络平均延迟并不算高,但是丢包严重,导致剧烈抖动乃至无法串流。
因此服务端和客户端优先选择相同运营商的网络,网络延迟在几十 ms 的时候都是可以流畅串流的,更重要的是网络抖动。
网络抖动
串流对网络抖动很敏感,隔三岔五的抖动非常影响体验,因此服务端和客户端都尽量使用有线网络,这样网络抖动可以显著降低。尤其是服务端,如果网络不稳定,自然会影响所有客户端。
如果实在缺少有线网络的环境,或者客户端是移动设备,也务必避免使用 2.4GHz 的 Wifi,因为很容易受到外部环境干扰,导致频繁抖动。尤其是蓝牙设备(耳机 / 手柄)和 2.4GHz 的 Wifi 在一个频段上,会相互干扰,出现不可忍受的网络延迟。
手柄连接
客户端设备连接上手柄后可以通过手柄直接操控 Moonlight 界面来启动或者退出串流,长按 Start 可以在串流中开启 / 关闭右摇杆的鼠标模拟功能。退出当前串流的按键组合是 Select + Start + LB + RB。
由于客户端可能运行在多种操作系统环境下,因此推荐使用 Xbox 手柄,各个操作系统都能兼容,或者至少使用带有 XInput 的第三方手柄。
另外需要关注的是手柄的振动功能。我只测试过 Xbox One/Series 以及 PS5 DualSense 手柄,总结如下:
Windows 对各种手柄的支持最全,可以有线或者无线连接,均支持振动。
MacOS 支持 Xbox/PS 手柄的无线连接,有线连接的时候往往只是给手柄供电,并没有实际的数据交互,此时仍然需要通过开启无线连接来正常使用。支持振动。
iOS/iPadOS 和 MacOS 类似,需要至少升级到 14.5 版本。
Android 设备对手柄的支持力度最弱,一个是因为 Android 本身对振动的支持并不好(需要 Android 层面和 Linux 内核层面的双重支持),另一个是 Android 设备往往缺少长期支持,大量设备无法升级到较新的版本(这点 iOS 设备好很多),导致不能识别手柄。推荐至少使用 Android 12,该版本中引入了基本的手柄振动功能。具体来说:
从 Android 10 开始(可能更早),Xbox 手柄可以通过有线 / 无线连接,但是从 Android 12 开始才支持有线连接下的振动,无线连接目前不支持振动。预计基于 Linux 6.6 内核的 Android 15 新设备可以支持无线连接下的 Xbox 手柄振动。
从 Android 12 开始支持 PS5 DualSense 手柄的有线 / 无线连接,均支持振动。
部分安卓厂商可能会自带额外驱动或补丁,具体行为需要自测。
如果 Android 设备的版本太老,有线连接下无法识别 Xbox 手柄或者没有振动,可以在 Moonlight 客户端的配置中开启自带的 Xbox 手柄 USB 驱动,并且勾选 “覆盖安卓手柄支持”,Moonlight 客户端自带的 Xbox 手柄驱动支持有线振动。
需要注意的是,Moonlight 仅能提供基本的振动,各个手柄特有的振动功能(例如 Xbox 手柄的扳机振动,PS5 手柄的触觉反馈)是无法实现的。如果需要此类振动,只能将手柄直接连接到服务端电脑,Moonlight 客户端仅用来传输画面。
关于 PS 手柄的建议:windows 上的游戏普遍对 xbox 手柄的支持最好,对于 PS 系手柄的支持就参差不齐了:有些游戏仅支持 xbox 手柄,有些游戏虽然支持 ps 手柄,但是功能不全(比如没有振动)。Sunshine 会自动识别手柄属于 xbox 还是 ps 系列,导致使用 ps 手柄的时候部分游戏支持不佳。为了最大的兼容性,可以考虑在 Sunshine 的 Configuration -> Input 页面,把模拟的手柄类型从自动改为 xbox,这样即使使用 ps 系列的手柄连接 moonlight,也会被游戏认作 xbox 手柄。
电视串流
现在的电视基本都自带了安卓,所以也能在电视上安装 Moonlight,再连接一个无线手柄,就可以直接在电视上游玩,无需将 PC 搬到电视旁边。而且现在哪怕是中端型号的电视也支持 4k 120Hz 和 HDR,只要电脑能够带得动游戏的高画质,就可以在电视大屏幕上享受。
与手机平板不同,电视的更换频率低很多,因此硬件和安卓版本都可能比较老旧,可能遇到的障碍有:
- 电视的安卓版本太低,不支持手柄的无线连接。考虑加装一个高版本的电视盒子,在电视盒子上安装 Moonlight;或者距离允许的话,用手柄直接无线连接服务端 PC,这样还能有 PC 原生的手柄振动支持。
- 电视硬件太旧,运行 Moonlight 吃力。同样考虑加装电视盒子。
- 如果电脑和电视都支持 4k 120Hz,那需要超过百兆的网络传输速率。此时如果想通过网线连接电视来保证最低的延迟,就会发现哪怕是目前的旗舰电视,网口也只有百兆。对于这种情况,要么退而求其次,使用无线网络,要么购买 USB 网卡,前提条件是电视至少是 Android 10 版本,并且有 USB 3.0 接口。推荐的 USB 网卡芯片是 RTL8153 或者 RTL8153B,这两个型号的兼容性最好,其中后者的能耗和稳定性更佳。不过 USB 网卡往往不会标注使用的芯片,或者不同批次使用不同型号的芯片,拿不准的话可以在某宝上直接搜索芯片名称,和商家确认。
虚拟屏幕
Sunshine 需要 PC 外接显示器才能投屏,也就是在 PC 的显示设置里能看到显示器。有些显示器哪怕关闭屏幕,只要和 PC 之间的线连着,PC 重启或者唤醒后仍然可以识别到;而有些显示器如果关闭了屏幕,那么 PC 重启或者唤醒后,就识别不到显示器了,此时通过 Moonlight 去连接,会出现黑屏无法操作。考虑到作为串流服务端的 PC 所外接的显示器往往是关闭的(甚至没有显示器),因此需要确保 PC 总能找到一个显示设备。
一个方案是购买硬件欺骗器,类似于 U 盘,插在电脑的显示端口上,充当一个虚假的显示器。好处是方便操作,兼容性强;坏处是需要额外的成本,而且常规的欺骗器只支持到 4k 60Hz,如果想要 4k 120Hz HDR 等更高的规格,需要花更高的价钱去定制。
更推荐的是软件模拟的方案。从 windows 10 开始自带了对虚拟屏幕的系统支持,通过安装自定义用户驱动就能随意创建任意分辨率和刷新率的虚拟屏幕。如果操作系统版本不低于 windows 11 23H2,创建出来的虚拟屏幕还支持 HDR。相关的软件不止一种,比如下面链接里的:
具体使用方式参考软件说明。虽然这个软件比较简陋,但是完全够用了,只需要创建并编辑配置文件,就能随意指定虚拟屏幕的参数。
外网方案
如果想脱离局域网,能够出门在外的时候也能串流到家里的电脑上,就需要规划外网方案。由于每个人的网络环境千差万别,只能因地制宜,对网络知识要求不低,因此这是串流里最难的一个环节。整体思路还是推荐家里能有一个开放系统的路由器,否则许多定制化的网络操作难以实现。
小白用户推荐使用虚拟局域网方案,其他方案不适合新手。
虚拟局域网
一个相对简单的方案就是组建虚拟局域网,相当于将本来不在一个局域网里的设备划分到一个虚拟局域网中,这样就可以跨网络相互访问,仿佛大家都在同一个局域网内,常用于企业的远程办公系统。
这里推荐 ZeroTier 软件,支持各种主流操作系统,傻瓜式操作,具体教程自行搜索,在服务端和客户端设备上都安装后,将它们都配置在一个虚拟网络里,然后在 Moonlight 中添加机器,填写服务端在虚拟局域网里的 ip 地址,就可以跨网串流了。
虚拟局域网的质量取决于服务端和客户端的网络环境,如果双方网络的连通性较好,则可以做到点对点直连,不需要走第三方中转,网络延迟相对比较有保障,和其他方案相比延迟区别不大,只是稳定性稍低一些;如果连通性较差,则只能走第三方中转,网络质量比较恶劣,想提升的话需要更复杂的网络方案,投入产出比低很多。
只要不是奇葩的网络环境,通过 ZeroTier 组建虚拟局域网是一个对小白比较友好的方案,哪怕还有其他方案,这个方案也可以作为备用链路。
公网 IP
本部分是写给对计算机网络知识比较了解、动手能力比较强的老司机的,只包含整体思路。如果不知道什么是公网 IP,就不用继续看了。
注意:有好奇心的小白用户在尝试前务必弄清楚公网 ip 的概念。一个简单的判断方法是随便找一个 ip 地址归属地查询网站,查询一下自己准备使用的 ip 地址,如果查询网站没有给出这个 ip 对应的地理和运营商信息,而是告知这是内网 / 局域网 ip,那就说明这个 ip 地址不是公网 ip。
IPv4
理想状态是能分配到公网 IPv4 地址(不需要固定)。目前国内家庭宽带里电信 / 联通用户可能可以获取公网 IPv4 地址,移动用户比较困难。
有了公网 IPv4 地址后,需要将家里的光猫改造成桥接模式,用自己的路由器拨号上网,这样路由器就拥有了公网 ip,可以从外网直接访问到这台路由器。随后开启路由器的 upnp 功能,同时在 Sunshine 的 Configuration->Network 下面也开启 upnp,准备工作就完成了(一般不需要手动配置 unpn 转发规则)。最后一步是在外网环境下打开 Moonlight,手动添加机器,直接填写路由器的公网 IPv4 地址,如果一切顺利的话就能识别到家里的 PC,达到远程串流的目的。
如果没有公网 IPv4 地址,那就退而求其次,使用 IPv6 地址。目前国内的三大网络运营商(电信 / 联通 / 移动)都提供家庭宽带的公网 IPv6 地址,电信 / 联通 / 移动的公网 IPv6 地址分别以 240e/2408/2409 开头。只要在路由器中开启 IPv6 功能,家里所有设备就都拥有了公网 IPv6 地址。之后在 Sunshine 的 Configuration->Network 下面开启 IPv4 + IPv6 选项,就能让 Sunshine 跑在公网 IPv6 地址上。
但是做到这些还不够,路由器往往都有防火墙,默认阻止外网流量访问内网,需要在路由器上把串流使用到的端口加入防火墙的 IPv6 白名单,具体使用了哪些端口可以在 Sunshine 的 Configuration->Network 页面上查看。添加白名单的操作步骤因具体路由器而异,IPv4 和 IPv6 各自有一套白名单,注意区分。
最后在 Moonlight 里添加机器的时候,填写 Sunshine 所在机器的公网 IPv6 地址就可以了。注意填写的格式为 [ipv6 地址],有一对中括号。如果要指定端口,那就是 [ipv6 地址]: 端口号。IPv6 方案是客户端直连 Sunshine 机器,所以填写的是 Sunshine 机器的 IPv6 地址,而之前的 IPv4 方案是客户端去连接路由器的 IPv4 地址,依靠路由器的 upnp 功能转发 IPv4 流量到 Sunshine 机器。
此方案的局限性:
需要服务端和客户端都在 IPv6 环境下才可以连通,而可以使用 IPv6 的环境比较有限,一般只出现在家庭宽带,手机的移动网络,以及一些教育网环境。这就导致虽然家里有了 IPv6 公网,但是出门在外的网络环境因为不受自己控制,往往只有 IPv4(例如商场、酒店等地方的 Wifi 热点)。外出时最有保障的 IPv6 网络环境其实是手机网络,但是串流的流量消耗很高,手机套餐的流量难以长时间支撑。
DDNS
家庭宽带下,不论是 IPv4 还是 IPv6 的公网地址,都不是固定的,不定期会发生改变。所以需要将公网 ip 地址映射到一个固定的域名上,并且定时更新(例如每 10 分钟)。这样在 Moonlight 里就可以填写域名,而不用去关注具体的 ip 地址。
这种方式也即是 DDNS 方案。提供域名的服务商有很多,免费和收费的都有,串流的场合下免费域名就够了。IPv4 场景下需要给路由器的公网 IPv4 申请域名;而 IPv6 的场景下需要给 Sunshine 机器的 IPv6 公网地址申请域名,也推荐同时给路由器的 IPv6 地址申请一个域名,这样在没有 IPv4 公网地址的情况下也可以从外部访问路由器,远程管理网络(需要在路由器上开启外网访问路由器管理页面的权限)。至于如何定时更新 IP 地址,需要自行摸索,比如有的路由器自带更新地址功能,有的域名服务商提供自动更新的软件。
远程唤醒
除非 PC 设置了永远不休眠,否则一段时间不操作,PC 就进入休眠状态,不再响应串流请求。所以需要给 PC 开启 WOL 功能,可以在局域网内通过网络请求唤醒 PC。为此要在 BIOS 以及网卡驱动里分别开启对应功能,如果是通过有线网络唤醒,那就更改有线网卡的配置,如果是通过无线网络唤醒,那就更改无线网卡的配置。通过有线网络的唤醒更可靠一些,不过实测无线网络唤醒也是可以正常工作的。参考如下教程:
如果是在局域网内,Moonlight 启动后会自动发送唤醒请求,不用手动操作。如果在外网环境就麻烦一些了,因为唤醒请求只在局域网里有效,没法直接在公网上唤醒设备。整体的思路是要有一个不会休眠的设备,拥有公网 ip,而且处于局域网内,由它代为发送唤醒请求。这个设备一般就是家里的路由器,而不少路由器系统(尤其是开放路由器系统)是提供相应的用户界面来手动唤醒局域网里的任意设备。这种场合下,只要通过路由器的公网 IP 登录路由器的管理页面,就可以在外网唤醒机器了。
另一个方案就是购买名为开机棒的智能硬件,通过开机棒提供的软件来远程唤醒,本质上还是 WOL,不过比较省心省力。
断电处理
如果突然停电导致机器关机,那就无法通过网络唤醒了。需要在 PC 的 BIOS 里的电源管理部分,配置类似于 “(非正常关机时)上电后自动开机” 的功能,这样恢复供电后 PC 会自动开机。具体如何配置,各个 BIOS 并不相同,自行摸索。
市面上也有智能插座硬件,可以使用智能插座提供的软件远程开启或关闭 PC 的电源。通过这种远程控制供电的方式,配合上电自动开机的设置,也可以间接做到远程唤醒 PC。

.jpg)
.jpg)
.jpg)