1. 现象全记录:麒麟 2403 无显示器开机后,x11vnc 连接到底看到了什么
先说结论:这个问题真实存在,并且不是桌面崩了,也不是显卡坏了,更不是重装桌面就能解决的事。我在一台麒麟 2403 的系统上折腾了整整一天,最后只花十几块钱就彻底解决了。为了避免后来人继续在“重装桌面—花屏—再重装”的循环里浪费时间,我把现象、排查步骤和能复现的解决方案原原本本写在这里。
这台机器是放在机房的,平时不需要接显示器,我用 x11vnc 远程连过去管理桌面。最开始一切正常,后来机房环境调整,显示器被收走了,我直接把机器拔电重启。重启之后,用 VNC Viewer 连上去,画面直接给我来了个“花屏现场”:窗口标题栏能隐约辨认,但大面积颜色块、横纹撕裂、鼠标拖动窗口时拖影严重,整个桌面像是掉进了老式电视机的雪花信号里。
我当时第一反应是桌面组件坏了,毕竟麒麟这类系统偶尔会因为更新残留导致桌面渲染异常,于是二话不说重装了桌面环境。第一次重装完重启,问题还在;我不死心,又重装了一轮,顺便还重建了用户配置目录,结果依旧花屏。这个时候我才冷静下来,意识到问题可能根本不在桌面本身,而是“无显示器开机”这个前置条件出了问题。
后面的排查方向就清楚多了:先看 Xorg 日志,再看 xrandr 输出,最后把显示器临时接回去做对比测试。实测下来,插上显示器启动,VNC 画面完全正常;拔掉显示器冷启动,花屏必现。到这里,基本确认问题出在显示链路初始化上,而不是麒麟桌面或 x11vnc 软件本身。
1.1 先用一张表看明白:不同状态下 x11vnc 画面表现
| 启动方式 | x11vnc 连接画面 | 诊断判断 |
|---|---|---|
| 插显示器正常启动 | 桌面清晰、颜色正常、操作流畅 | 显示链路没问题,桌面和 VNC 软件没坏 |
| 不插显示器冷启动 | 花屏、色块、撕裂、分辨率异常 | GPU/内核没有得到有效显示器信息,用了错误的显示模式 |
| 不插显示器重启桌面服务 | 仍然花屏 | 单纯重启桌面不解决底层显示模式问题 |
| 插上显示器后热拔再启动 x11vnc | 短暂正常,拔掉后可能恢复花屏 | 每次重启都可能重新触发显示初始化问题 |
这张表是我实际测试得出的结果,看完基本就能把“重装桌面”这个选项从脑海里划掉。桌面环境只是运行在 X 显示服务之上的上层应用,如果底层 Xorg/KMS 在初始化时拿到的显示器信息就是错的,上层界面再怎么重装也是白搭。
1.2 真正值得先做的两件事:查日志和看分辨率
遇到花屏,先不要急着卸软件,打开两个工具看一下,几十秒钟就能定位一大半问题。第一个是 xrandr,第二个是 Xorg 日志。
# 查看当前显示输出状态 xrandr --listmonitors xrandr -q # 查看颜色深度 xdpyinfo | grep depth # 查看 Xorg 运行日志中的错误和警告 grep -E "(EE|WW|mode set|failed)" /var/log/Xorg.0.log | tail -50我在这台机器上执行 xrandr 的时候,输出只有一行 640x480 或者 1024x768 的默认模式,HDMI/VGA 接口全部显示 disconnected,而且颜色深度掉到了 8bit 或 16bit 而不是正常的 24bit。这基本就是我遇到的花屏画面的根源:桌面在极低分辨率、低位色深下被强行拉起来,界面文字、背景、控件混在一起,颜色过渡全是色带,看起来就是典型的“花屏 + 色彩断层”。
Xorg 日志里也写得比较直白,会出现类似 “No EDID data” 或 “no modes found for output HDMI-1” 的信息。EDID 是显示器通过数据线发给显卡的一串参数,包含分辨率、刷新率、色深等标准信息。没有接显示器,显卡就收不到 EDID,于是只能按一个保守的兜底模式初始化,桌面自然就以一种非常难看的姿势跑起来。
2. 花屏根因拆解:EDID、KMS 和桌面合成器是怎么“联手捣乱”的
既然排除了软件层面的问题,那就必须把“无显示器开机”背后的机制讲清楚。很多人花屏之后习惯性重装桌面,就是因为不清楚显卡在开机时到底依赖什么信息来决定显示参数,以为只要软件是完整的,界面就应该正常。
家用台式机或服务器如果长期不接显示器,显卡的显示输出口在开机自检阶段检测不到任何“显示器在线”信号,GPU 就会认为这个输出空闲。到了内核里面的 KMS(Kernel Mode Setting)接管显卡的时候,每个输出接口对应的状态就是 disconnected。KMS 是内核负责设置显示模式、分辨率、刷新率和显存布局的子系统,显示输出没有连接设备,它就不会分配一个合理的模式列表。
Xorg 在 KMS 之上运行,它从内核拿到模式列表,发现列表几乎是空的,于是只能使用内部的兜底模式。这个兜底模式在大多数驱动里是 1024x768 或 640x480,颜色深度也可能退化成 8bit。麒麟桌面的 UKUI 会话起来之后,界面按这个“残废模式”绘制,再由 x11vnc 把屏幕画面编码发送给客户端,远端自然看到的就是色块、撕裂、色彩断层交织的花屏画面。
2.1 没有 EDID,显卡就像“没有尺子的裁缝”
EDID 这个东西值得单独说一下。显示器通过 HDMI、DP、DVI、VGA 线缆向显卡发送一串 128 字节左右的数据,这串数据里写明了显示器支持的扫描频率、物理分辨率、色彩空间、厂商信息等等。显卡拿到 EDID 之后,才能确定“我该按什么分辨率输出”,本质上相当于裁缝拿到了一件衣服的尺寸数据,知道该怎么下剪子。
没有显示器的时候,显卡收不到 EDID,KMS 就拿不出正规模式列表,Xorg 只能自己随便剪一块布,出来的桌布当然不可能合身。这也是为什么我接入显示器之后一切正常,拔掉显示器重启就花屏:插入显示器意味着 EDID 信号回来了,显卡知道该干正事了;拔掉之后信号又断了,但因为你没重启,驱动层面还暂时保留着旧模式,所以热拔之后短时间内还能看,一旦彻底重新开机就现出原形。
2.2 桌面合成器在无头模式下更容易暴露问题
麒麟桌面默认开启了窗口合成特效,比如窗口阴影、透明、动画等。这些特效依赖 X 的合成扩展(Composite)和 DRI/OpenGL 渲染。有显示器时,GPU 会正常工作,合成器也从帧缓冲里读到合适的画面;无显示器环境下,分辨率低、色深浅、帧缓冲布局怪异,合成器很容易出现渲染同步问题,表现到 VNC 上就是拖影、撕裂、局部残影。
x11vnc 默认使用 XDamage 扩展来获取屏幕变化区域,然后增量转发给客户端。如果底层渲染已经混乱,x11vnc 拿到的“变化区域”也是乱的,远端画面自然就会持续出现色块残留。这种情况下,单纯调整 x11vnc 参数只能缓解,不能根治,真正的解决思路还是要让显卡在无显示器状态下拿到一份合格的显示参数。
2.3 为什么“重装桌面”是彻底的无效操作
桌面环境是运行在 X 服务之上的一层软件,它本身不负责决定显示器的分辨率、色深和刷新率。花屏问题的根源在更底层:显卡驱动和内核 KMS 在初始化时缺少 EDID,才导致桌面被迫运行在异常模式下。重装桌面只是把上层软件恢复到了默认状态,底层显示模式依然没有被修正,重启之后桌面还是会被拉到那个错误的分辨率和色深上。
说句实在话,我后来复盘时觉得自己那两次重装毫无必要,白白浪费了一个下午。麒麟系统的软件源在自己的仓库里,重装桌面环境拉包、解包、重建配置,少说半小时,多则一小时,结果问题原封不动。这个教训就是:遇到显示类故障,先查底层显示链路,再怀疑桌面组件。
3. 方案 A(首选):十几块钱的“显示器模拟插头”,无头模式的稳准狠方案
如果你问我现在碰到无显示器 + VNC 花屏,最省心的方案是什么,我会毫不犹豫地说:花十几块钱买一个虚拟显示器插头,也叫 EDID 模拟器、HDMI/DVI/VGA 诱骗器。这玩意儿就是个接口插头,内部有 EDID 芯片,插在显卡的输出口上,显卡就会认为有一台显示器在线,从而输出正常的分辨率和色深。
这些插头在电商平台上很常见,搜“HDMI 诱骗器”“EDID 模拟器”“虚拟显示器”都能找到。买回来之后直接插在显卡的主输出口上,重新开机,让 KMS 在初始化时读到这个假 EDID,桌面就会按照正常模式启动了。后续再用 x11vnc 连接,画面就能保持清晰不花屏。这个方法本质上是给无头服务器补上了一个看不见的显示器,成本极低,稳定性最高。
3.1 选购时要注意的四个点
第一是接口类型,得看你的显卡或者主板输出口是 HDMI、DP、DVI 还是 VGA,买对应接口的插头。第二是支持的分辨率,尽量选支持 1920x1080@60Hz 甚至 4K 的版本,不要买那种仅支持 640x480 的老式诱骗器,否则 VNC 里看到的分辨率会低到没法用。第三是是否支持热插拔,有些廉价版本只在开机时生效,系统运行中拔插头可能导致模式变化,最好买稳定输出固定分辨率的产品。第四是供电方式,HDMI 和 DP 诱骗器一般不需要额外供电,VGA 版本则要看芯片方案,部分需要 USB 供电。
3.2 插上之后需要做的验证步骤
插上插头后,建议直接重启系统,让显卡在冷启动阶段就拿到 EDID,而不是在运行中再插入。重启完成后,先在本地终端或者 SSH 里执行xrandr -q,确认输出口状态变成了 connected,并且能看到 1920x1080 或你期望的分辨率。再执行xdpyinfo | grep depth,确认颜色深度是 24bit 或 32bit,而不是 8bit/16bit。
确认无误后,再把 x11vnc 跑起来,用 VNC Viewer 连接。此时看到的桌面应该是完整、清晰、颜色正常的,拖动窗口、切换应用程序都不会再有明显的色块和撕裂。这个方法最稳的一点在于:它从底层补上了 EDID 信号,Xorg/KMS/合成器全链路都按正常显示器逻辑工作,后续基本不用再调其他参数。
4. 方案 B(纯软件):不花一分钱,用虚拟显示器模式把分辨率/色深撑起来
如果你手头没有诱骗器,又暂时不方便买硬件,也有纯软件的办法可以尝试。这个方案分两种情况:一种是内核自带虚拟显示模块(如 vkms),另一种是 Xorg 层面配置虚拟输出或强制指定分辨率。两者的原理都是“无中生有”给系统造出一个显示器,让 KMS 认为有输出设备在线。
先说 vkms。vkms 是内核里的虚拟 KMS 驱动,它不依赖真实硬件,可以在没有物理显示器的机器上创建一个虚拟显示输出。如果你的麒麟 2403 内核编译时带上了这个模块,可以直接加载试试:
# 检查当前内核是否支持 vkms modinfo vkms # 如果存在,加载模块 sudo modprobe vkms # 查看模块是否加载成功 lsmod | grep vkms # 重启显示管理器 sudo systemctl restart lightdm重启显示管理器之后,再执行xrandr -q,如果能看到一个虚拟输出口,说明 vkms 生效了。这个虚拟口可以被分配正常分辨率,桌面会按照标准色深启动,花屏问题就迎刃而解。为了让模块在重启后自动加载,把模块名写入模块加载配置即可:
echo "vkms" | sudo tee /etc/modules-load.d/vkms.conf不过要提醒一点,麒麟系统不同版本、不同内核,是否包含 vkms 模块并不完全一致。如果modinfo vkms提示找不到模块,可以先试着通过软件源安装内核扩展包,比如linux-modules-extra-*这类包,装上后再检查一次。
4.1 用 xrandr 强制添加模式:适合部分支持虚拟输出的显卡
另一种软件思路是用 xrandr 手工生成一个 mode,然后添加到某个显示输出上。这个办法能不能成,完全取决于显卡驱动是否允许你在 disconnected 状态下手动绑定模式。我在部分装有 NVIDIA 闭源驱动的机器上成功过,NVIDIA 的驱动可以把 DFP(Digital Flat Panel)输出强制绑定一个虚拟模式。
如果你是 AMD/Intel 显卡,可以先试试 VIRTUAL 输出是否存在。执行xrandr -q,如果输出列表里有一个名字类似VIRTUAL1、VGA1、HDMI1的口,可以生成模式并绑定:
# 用 cvt 生成一个 1920x1080 60Hz 的 modeline cvt 1920 1080 60 # 把 modeline 里的参数复制到下面,创建一个新 mode xrandr --newmode "1920x1080_60" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync # 添加到输出口 xrandr --addmode HDMI-1 1920x1080_60 # 激活 xrandr --output HDMI-1 --mode 1920x1080_60如果--addmode报错提示输出口没有可用的 CRT,说明驱动在这种无显示器状态下根本不允许绑定虚拟模式,这条路就走不通。此时不要硬磕,优先考虑 vkms 或者硬件插头。
4.2 通过 Xorg 配置强制指定默认分辨率的兜底办法
还有一种老办法,是给 Xorg 写一个配置文件,在驱动层面强制指定默认显示模式。比如创建/etc/X11/xorg.conf.d/20-headless.conf,内容大致是让 Xorg 在启动时固定使用 1920x1080 的模式。不过这个方法在现代 KMS 渲染路径上不一定总是生效,因为内核 KMS 掌握最终输出话语权,Xorg 侧的配置可能被覆盖。
我个人的实践感受是:软件方案里 vkms 成功率最高,xrandr 强绑要看显卡脸色,Xorg 配置则适合 X11 传统驱动路径。如果这三个都不行,还是老老实实回到硬件插头,不要和显卡驱动的初始化逻辑硬刚,因为没有 EDID 的底层问题,本质上就是一个硬件链路信息缺失的问题,软件能补的情况是有限的。
5. 方案 C:换个思路调 x11vnc,把远程画面“搬”到虚拟会话里
如果你不是非要用实体桌面会话,还有一种更干净的做法:放弃跟随物理桌面,直接创建一个独立的虚拟 X 会话,把 x11vnc 挂在虚拟会话上。这个方案的好处是,虚拟会话不依赖物理显卡的 EDID,我自己创建的帧缓冲是什么分辨率、什么色深,它就用什么,完全没有花屏问题。
具体操作用到 Xvfb(X Virtual Framebuffer),它在内存里模拟一块虚拟显示区域,不输出到任何物理接口。先将 Xvfb 跑起来,再在它上面启动 x11vnc,远程连接的时候看到的就是一个干净、稳定、分辨率可控的桌面或命令行界面。
# 安装 xvfb sudo apt install xvfb -y # 启动一个 1920x1080、24 位色深的虚拟显示,编号为 :1 Xvfb :1 -screen 0 1920x1080x24 -ac & # 把 x11vnc 挂到 :1 上,端口用 5901 x11vnc -display :1 -rfbport 5901 -passwd yourpassword -forever -shared & # 这时在 VNC Viewer 里连接 IP:5901,就能看到虚拟桌面如果需要在这个虚拟会话里启动一个轻量桌面,可以直接设置DISPLAY=:1后启动桌面会话组件。麒麟桌面完整跑起来会偏重,但如果只是偶尔远程执行图形配置工具,Xvfb + x11vnc 的组合足够用了。它最大的优势是从数据结构上绕开了“无显示器”这个坑,因为虚拟显示根本不在意物理显示器是否存在。
5.1 实体会话下,x11vnc 参数怎么调才不容易出伪影
如果还是想在实体会话里用 x11vnc,不搞 Xvfb,那么至少要把启动参数调到最不容易出伪影的状态。我之前遇到过一开窗口动画远端就拖影子、拉出彩条的情况,主要就是 x11vnc 和合成器之间的 damage 事件没配合好,尝试在启动参数里禁用 XDamage 并固定色彩空间之后,画面明显干净很多。
x11vnc -display :0 \ -rfbport 5900 \ -passwd yourpassword \ -forever \ -shared \ -noxdamage \ -viewonly \ # 如果只读需求,加上这个更省心 -visual TrueColor \ -logfile /var/log/x11vnc.log这里的-noxdamage是让 x11vnc 不要依赖 XDamage 扩展来判断屏幕变化区域,改用整帧轮询和比对,虽然 CPU 占用会高一些,但不容易出现合成器引发的残留伪影。-visual TrueColor是强制使用真彩色彩空间,避免客户端收到低色深或伪色模式导致的色块断层。两者可以在很大程度上缓解“花屏感”,但要注意,如果底层 EDID 问题还在,光靠这些参数救不回来,只能作为辅助手段。
5.2 用 systemd 守护 x11vnc,顺便解决开机自启时想手逮不到的问题
无头服务器场景下,另一个很常见的痛点是想开机就自动把 VNC 服务拉起来,结果每次都要手动敲命令。与其把 x11vnc 扔到 rc.local 里碰运气,不如写一个 systemd 服务,并在里面等待 X 显示服务就绪。
[Unit] Description=x11vnc remote desktop helper After=display-manager.service Wants=display-manager.service [Service] Type=simple User=yourname Environment=DISPLAY=:0 ExecStart=/usr/bin/x11vnc -display :0 \ -rfbauth /home/yourname/.vnc/passwd \ -forever -shared -noxdamage \ -rfbport 5900 \ -logfile /var/log/x11vnc.log Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target把文件写到/etc/systemd/system/x11vnc.service,然后执行sudo systemctl daemon-reload && sudo systemctl enable --now x11vnc即可。这里的After=display-manager.service很关键,如果显示器服务没起来就启动 x11vnc,它会因为找不到:0这个 display 而直接退出。先确认你的麒麟系统用的是哪一个显示管理器,我的环境里是 LightDM,所以写display-manager.service;如果你系统里是 GDM 或其他,命名也要对应调整。
5.3 密码文件权限踩过的坑
x11vnc 用-rfbauth参数时,密码文件要用x11vnc -storepasswd生成,并且权限要设置成只有当前用户可读写。我用 systemd 启动时遇到过一次“密码文件无法读取”的报错,查下来就是因为文件在 root 用户初始化时生成,普通用户无法读取。解决方法是:
x11vnc -storepasswd yourpassword /home/yourname/.vnc/passwd chown yourname:yourname /home/yourname/.vnc/passwd chmod 600 /home/yourname/.vnc/passwd这个坑虽然小,但很容易让人误以为服务启动失败或者 x11vnc 装坏了,实际上只是权限问题。遇到自启失败,先systemctl status x11vnc -l看日志,再逐行对照路径和权限,比盲目重装靠谱得多。
6. 落地操作顺序:从重启验证到开机自启,一步步复现可用的稳定方案
单独看上面几个方案,可能有人会看晕,不知道先做哪个。这里我给出一个实际落地顺序,你按着这个顺序走,基本能在半小时内把花屏问题解决掉,不需要碰系统重装。
第一步,先查清楚自己的硬件和连接状态。机器如果就在手边,优先花十几块钱买一个虚拟显示器插头,这是最省事、最稳定、最不影响业务的做法。如果机器在远端机房不方便买硬件,就先尝试 vkms 软件方案,能用就不花钱。
第二步,不管用哪个方案,先改完再重启,不要运行中改一半就测试。因为 EDID 问题本质上是开机初始化阶段的链路问题,热拔插或重启显示管理器不一定能把 KMS 的状态洗干净,冷启动验证最准确。
第三步,验证命令统一用这三条:
xrandr -q xdpyinfo | grep depth ss -tlnp | grep :5900第一条看分辨率,第二条看色深,第三条看 VNC 端口是否监听。确认没问题后,再用 VNC Viewer 连接画面,如果画面清晰、色彩正常,说明问题已经解决。
第四步,把 x11vnc 整理成 systemd 服务,避免下次重启后又要手动拉起。上面的 systemd 配置直接复制改成自己的用户名、密码文件路径、端口即可。
6.1 如果方案都试了还是花屏,可能是桌面合成器在作怪
还有一种少数情况:底层 EDID 问题和分辨率问题都被解决了,但 VNC 里依然能看到些微撕裂或残影。这种情况下,很大概率是桌面合成器和 x11vnc 的抓屏方式不兼容。可以先尝试在麒麟桌面的“特效”设置里,把桌面特效切换到“性能模式”或直接关闭窗口动画,再刷新 VNC 画面。
如果关闭特效后画面恢复,说明是合成器渲染路径和 x11vnc 之间的小冲突,用-noxdamage参数可以缓解大部分,剩下的靠禁用特效收尾。如果你确实不想关闭特效,那就只能接受极少量的画面残留,不影响操作,也不至于花屏到看不清。
6.2 已插显示器的机器,为什么偶尔也会花屏
顺便多说一句,如果你的机器明确插着显示器,但 VNC 仍然花屏,那就要检查另一类问题:线缆质量、转接头、显示器电源、显卡供电。特别是 HDMI 转 VGA 这种主动式转接头,很容易在分辨率较高的场景下出现信号干扰,导致 EDID 读取不稳定。这类问题容易和“无显示器花屏”混淆,排查时建议先把物理链路的嫌疑排除掉,再考虑系统层面。
7. 踩坑记录与排查速查表:这些问题我也一个个踩过
最后把我在这次折腾中遇到的典型问题和对应的处理办法整理成一张速查表,方便你直接对照。每一个问题都是实际踩过的坑,不是网上抄来的“通用答案”。
| 现象 | 可能原因 | 优先处理办法 |
|---|---|---|
| VNC 画面大面积色块、色彩断层 | 无显示器导致色深掉到 8bit/16bit | 使用虚拟显示器插头或 vkms,把色深恢复到 24bit |
| 分辨率只有 640x480 / 1024x768 | 无 EDID,Xorg 使用兜底模式 | 补 EDID:物理插头、vkms、或 xrandr 手动强绑 |
| 拖动窗口出现拖影、撕裂 | 桌面合成器与 x11vnc damage 事件冲突 | 加-noxdamage,必要时关闭桌面特效 |
| x11vnc 服务自启后秒退 | X 服务尚未就绪,display 找不到 | systemd 加After=display-manager.service |
| 密码文件读取失败 | 密码文件权限或属主错误 | 重新x11vnc -storepasswd,权限设为 600 |
| xrandr 没有可用输出口 | 显卡驱动禁止 disconnected 状态下绑定模式 | 放弃软件强绑,改用硬件虚拟插头 |
| vkms 模块不存在 | 内核未编译该模块 | 尝试安装内核扩展包,或改用硬件方案 |
| 插着显示器也花屏 | 线缆、转接头或显卡供电不稳定 | 先换线、换转接头,再查系统设置 |
这张表基本覆盖了无显示器 VNC 花屏的主要分支。如果你遇到的情况不在表里,可以先把 Xorg 日志里包含EE、WW、EDID、mode的行都过一遍,很多时候日志里已经写出了真正原因,只是被大量无关信息盖住了。
我个人在实际操作中的体会是:这类问题最怕一上来就重装,软件重装解决不了硬件链路的信息缺失。先用插头或 vkms 把底层显示模式稳住,再调 x11vnc 和合成器参数,整个流程走下来既快又不伤人。最后再分享一个很小的技巧:把排查用的 xrandr、xdpyinfo、日志路径这三样东西记在手机的备忘录里,下次再遇到无头模式显示故障,照着走一遍就完了,省得满网重新找方案。