“无X11显示”相关错误含义和解决
1. 简介
我们习惯于使用图形用户界面 (GUI) 并使用其元素启动应用程序。然而,有时,我们必须使用来自终端的命令,并且可能会遇到诸如No X11 DISPLAY variable was set或Error: Can’t open display 之类的消息。在本教程中,我们将研究如何解决此类问题。
2.定义
X11或*X Window *是适用于大多数 UNIX 风格的图形系统。它于 1984 年在麻省理工学院 (MIT) 的Project Athena 中诞生。在麻省理工学院,数百个异构工作站分散在校园内。**这个想法是提供一个窗口系统来编写可以在任何工作站上运行的应用程序。**应该可以通过网络访问任何工作站上的应用程序并在本地查看图形输出。
2.1. 客户端-服务器模型和 Core X 协议
对于设备无关的应用程序,设备访问的细节隐藏在X Server 中。它通过处理来自 X 应用程序的连接、多路分解图形请求以及多路复用来自键盘、鼠标等的输入返回到应用程序来提供所有基本的窗口机制。应用程序通过进程间通信 ( IPC ) 路径连接到X 服务器,可以通过共享内存或网络协议(如TCP )。
这样的 IPC 路径称为X 客户端。由于大多数应用程序只打开一个连接,我们通常称应用程序本身为X 客户端。X 客户端和X 服务器之间的通信协议称为X 协议。它是构建其他工具的基础层。
2.2. DISPLAY是什么意思?
要在屏幕上创建窗口并接收事件,我们应该建立连接以显示。就X而言,显示器由一个或多个屏幕、一个键盘、一个(可选)指针设备和 X Server组成。默认情况下,应用程序使用存储在 shell 环境变量DISPLAY中的显示名称;这是以下格式的字符串:
- Host_Name:[:]Display_Number.Screen_Number
- Host_Name是显示器物理连接到的主机的名称。
- :[:] 我们只在与DECnet 联网的情况下使用双冒号。
- Display_Number是该主机上显示服务器的从零开始的编号。一台计算机可以有多个运行的服务器。
- Screen_Number(也从 0 开始)指定要在该服务器上使用的屏幕。单个X 服务器可以控制多个屏幕。
3.了解和设置DISPLAY
了解我们当前DISPLAY的最简单方法是使用echo this 变量或从set 命令给出的所有shell变量列表中grep it :
$~ echo $DISPLAY
:0
$~ set | grep DISPLAY
:0
在我们的示例中,通常缺少Host_Name和Screen_Number 。这意味着X 客户端将使用本地X 服务器和 IPC 传输进行通信。得到的值相当于unix:0.0 或 :0.0,这里的unix表示X客户端使用IPC。如果冒号前有Host_Name,则X 服务器和X 客户端通过 TCP 传输进行通信。
**通常,系统已经为我们设置了DISPLAY。**然而,在某些情况下,我们应该手动完成。手动确定它与任何其他 shell 变量相同。下面是直接设置它的例子:
$~ export DISPLAY=unix:0.0
为了测试我们的 DISPLAY 设置,我们通常尝试运行一个简单的程序,如xeyes或xclock。
4. DISPLAY is not set等类似问题
例如,如果我们从本地控制台启动xeyes并且它运行时没有任何杂音,则DISPLAY设置正确。如果我们使用命令unset删除DISPLAY并重新运行xeyes,它会报错:
$~ unset DISPLAY
$~ xeyes
Error: Can't open display:
使用java的应用程序也会报错:
$~ java -jar Paint.jar
Exception in thread "AWT-EventQueue-0" java.awt.HeadlessException:
No X11 DISPLAY variable was set, but this program performed an operation which requires it.
流行的浏览器chromium会发出类似这样的巨大输出消息:
$~chromium
[6864:6864:1126/221702.545428:FATAL:ozone_platform_x11.cc(232)] Check failed: x11::Connection::Get()->Ready(). Missing X server or $DISPLAY
在所有这些情况下,我们都会遇到不正确或缺失的关键字X server、DISPLAY。 然而, Qt程序的输出更复杂。它没有这些关键字,因为Qt是多平台应用程序的框架并且有很多依赖项:
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
因此,**错误消息取决于软件。**反过来,解决这个问题取决于我们想在哪里运行X 客户端,是在远程机器上,还是在本地机器上。
5. 启动远程X 客户端
**启动远程X 客户端的最佳方法是使用ssh 和所谓的X 转发 **,将X 协议数据包定向到我们用于命令的同一连接上。因此,我们将ssh -X our_remote_host并在登录后启动 X11 应用程序。
当然,如果ssh守护进程sshd 在远程端运行并且它的配置文件sshd_config 包含X11Forwarding yes行,就可以了。典型的DISPLAY值为localhost:10.0:
tiger@home:~> ssh -X tiger@gatti.net
Last login: Wed Dec 1 14:32:07 EET 2021 from home on pts/4
Have a lot of fun...
tiger@gatti.net:~> set | grep DISPLAY
DISPLAY=localhost:10.0
我们可以使用 -Y 键代替*-X* ,但只有适当配置此sshd才有意义。这两个密钥分别用于不可信和可信连接。受信任的人可以完全访问整个DISPLAY。他们可以进行键盘记录、屏幕截图和输入其他程序的窗口;它可以使用所有 X 服务器 扩展,如加速图形。可信连接可能适用于平稳运行应用程序,但无疑对安全性不利。
如果X 服务器接受 TCP 连接,我们可以使用xhost 方法。我们将用一个例子来展示它。
假设,我们坐在主机jaguar附近,想要连接并在远程主机tiger上运行X 客户端,但将其结果输出到本地,在jaguar上。
在与远程主机tiger建立连接之前,我们需要使用xhost命令将其添加到允许列表中,xhost +our_remote_host:
$~ xhost +tiger
tiger being added to access control list
xhost *+*也可以。但是,它的使用是危险的,因为客户端可以从任何主机连接到您的 DISPLAY,从而造成安全漏洞。
登录到tiger后,我们将**DISPLAY设置为在我们的本地机器上输出,在我们的例子中是jaguar:
$~ export DISPLAY=jaguar:0.0
完成并注销后,我们从列表中删除主机:
$~ xhost -tiger
localhost being removed from access control list
但是,这种方法在现代发行版上无法开箱即用,因为默认情况下禁止与X 服务器的 TCP 连接。
6. 在本地机器上启动
通常,我们直接从 GUI 启动应用程序,但在某些情况下,我们从konsole 或终端(如xterm 、gnome-terminal 或yakuake )启动应用程序。如果本地应用程序抱怨DISPLAY,我们可以尝试使用其他类型的终端。
如果尝试在sudo 命令后运行应用程序,我们可能会遇到DISPLAY错误。当然,我们可以通过ssh -X user@localhost来解决问题,但是如果由于sshd配置的限制不能这样做,我们也可以使用xhost或xauth方法。
6.1. 使用xhost方法
我们将使用一个示例来说明该方法。我们作为用户panter 登录。假设,panter需要以另一个用户lion的身份执行命令。为了保留DISPLAY值,我们将添加一个选项*-E*(或*–preserve-value*),但这还不够:
panter~> sudo -Eu lion xeyes
[sudo] password for lion:
Authorization required, but no authorization protocol specified
Authorization required, but no authorization protocol specified
Error: Can't open display: :0
有关授权的打印信息是我们解决此问题的关键。它提示我们需要将lion添加到允许的用户列表中。所以,在sudo之前,我们会这样做:
panter~> xhost +si:localuser:lion
localuser:lion being added to access control list
在此命令中,键si表示X 服务器将执行此连接。 这次我们可以运行我们的X 应用程序。完成后,我们从列表中删除用户lion :
panter~> xhost -si:localuser:lion
localuser:lion being removed from access control list
6.2. 使用xauth方法
我们可以将方法与xauth 一起使用。它允许任何知道密钥的人访问。此密钥称为魔术 cookie 或授权记录,授权方案名为MIT-MAGIC-COOKIE-1。我们还将通过相同的示例展示如何使用它。
我们首先使用xauth命令获取DISPLAY和密钥:
panter~> set | grep DISPLAY
DISPLAY=:0
panter~> xauth list $DISPLAY
panter.cats.edu/unix:0 MIT-MAGIC-COOKIE-1 abf87ea2c8a4ed7f41ce8e7b99047870
#ffff##:0 MIT-MAGIC-COOKIE-1 abf87ea2c8a4ed7f41ce8e7b99047870
然后,我们切换到lion并设置DISPLAY(或在 sudo 中使用*-E*键,如上例所示):
lion:~> export DISPLAY=:0
此外,我们注意到xauth输出;xclock无法运行。
lion~> xauth list $DISPLAY
xauth: file /home/lion/.Xauthority does not exist
lion~> xclock
Authorization required, but no authorization protocol specified
Authorization required, but no authorization protocol specified
Error: Can't open display: :0
此外,我们导出密钥;xclock可以运行:
lion~> xauth add $DISPLAY . abf87ea2c8a4ed7f41ce8e7b99047870
xauth: file /home/lion/.Xauthority does not exist
完成后,我们取出钥匙:
lion~> xauth rem $DISPLAY
缺少 $HOME/.Xauthority文件不是错误。如果缺少,将自动创建该文件。
我们还可以使用xauth方法在远程主机上运行X 客户端。这种方法比xhost方法安全得多。
7. 关于Wayland的注意事项
显示服务器与其客户端之间的新通信协议Wayland 越来越流行。
使用它也可能引起一些关于DISPLAY的抱怨。避免此类问题的最佳方法是使用ssh方法。但是请注意,并非所有X11应用程序都可以在Wayland下运行。
有一个特点:Wayland ssh客户端可能需要像Xephyr 这样的嵌套X 服务器,而Wayland ssh主机可能需要应用程序命令前的预设字符串,GDK_BACKEND=x11。Xephyr成为我们在客户端上的X11显示,我们指向Wayland主机使用X11在Xephyr窗口上运行应用程序。