共计 3223 个字符,预计需要花费 9 分钟才能阅读完成。
linux 环境下 Java 程序 UI 显示问题
问题形容
我的项目在 linux 环境下运行时,因为历史遗留起因,须要通过 UI 界面展现一个二维码供扫码应用。最常见的就是和 UI 相干的各种谬误了,比方上面这个:
Can’t connect to X11 window server using ‘:2.0’ as the value of the DISPLAY variable.
上面咱们通过一个简略的示例来探索一下 linux 下和 UI 相干各种谬误及其起因。
简略的样例程序
package my;
public class Test{public static void main(String[] args){System.out.println("java.awt.headless=\t" + System.getProperty("java.awt.headless"));
System.out.println("DISPLAY=\t" + System.getenv("DISPLAY"));
JOptionPane.showMessageDialog(null, "Hello!");
}
}
能够应用你相熟的任意工具将下面代码编译、并打包为一个 JAR 包,假如文件名为 test.jar
将 test.jar 上传到 linux 服务器特定目录下,假如寄存到 /opt 目录;
通过 SSH 客户端登录 linux
运行程序:$ java -cp test.jar my.Test
零碎输入如下:
java.awt.headless= null
DISPLAY= null
Exception in thread "main" java.awt.HeadlessException:
No X11 DISPLAY variable was set, but this program performed an operation which requires it.
at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204)
at java.awt.Window.<init>(Window.java:536)
咱们看到,通过 SSH 登录 linux 零碎时,以后会话缺省是没有设置 DISPLAY 环境变量的;而 Java 应用程序要展现界面须要 DISPLAY 环境变量指向可用的显示环境(即 X11Server 地址)
headless 属性的作用
如果咱们运行前,将 java.awt.headless 零碎属性设置为 true,后果是什么呢?
运行程序:$ java -Djava.awt.headless=true -cp test.jar my.Test
零碎输入如下:
java.awt.headless= true
DISPLAY= null
Exception in thread "main" java.awt.HeadlessException
at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204)
at java.awt.Window.<init>(Window.java:536)
设置 headless 并不能解决 UI 显示问题;它更像是一种提醒,告知以后零碎无奈应用图形环境;
启动第三方 XServer 服务
咱们尝试在 Windows 环境下启动 XServer 服务:windows 下局部 linux 近程工具通过内嵌 XServer 服务反对拜访 linux 图形界面,比方:XShell、MobaXTerm、XMing、X-Win32 等;
咱们这里应用一个收费的更纯正的 XServer windows 服务程序:VcXsrv
下载地址
启动 VcXsrv 当前 (留神放开拜访权限,配置时抉择:disable access control
),windows 状态栏会多出一个 VcXsrv 的任务栏图标,鼠标悬停在下面,会提醒以后 XServer 的拜访地址,比方xxx:0.0
其中,冒号前是主机地址,域名或 ip;冒号后的第一个数字代表 XServer 监听端口,这个数字 + 6000 即是真正的监听端口;
在 windows 命令行执行C:\> netstat -ano | find "600"
,显示如下;
TCP 0.0.0.0:6000 0.0.0.0:0 LISTENING 32472
TCP 127.0.0.1:6000 127.0.0.1:53790 ESTABLISHED 32472
TCP 127.0.0.1:6000 127.0.0.1:53791 ESTABLISHED 32472
TCP 127.0.0.1:6000 127.0.0.1:53792 ESTABLISHED 32472
TCP 127.0.0.1:53790 127.0.0.1:6000 ESTABLISHED 32472
TCP 127.0.0.1:53791 127.0.0.1:6000 ESTABLISHED 32472
TCP 127.0.0.1:53792 127.0.0.1:6000 ESTABLISHED 32472
TCP [::]:6000 [::]:0 LISTENING 32472
咱们看到本地监听的 TCP 端口 6000,这正是 XServer 过程关上的;如果咱们在启动 VcXsrv 时,端口设定为 -1
,则示意由 VcXsrv,从 6000 开始探测第一个可用的端口;
DISPLAY 环境变量指向近程 XServer 地址
咱们尝试在运行 java 程序前,指定 DISPLAY 环境变量如下:
# 10.1.27.33 替换为 windows 主机地址,:0 替换为 Xserver 监听端口减去 6000 的值
$ export DISPLAY=10.1.27.33:0
$ java -cp test.jar my.Test
运行程序,这时候咱们发现没有谬误了!只是咱们的界面在哪儿呢?别慌!看下 windows 任务栏,你将在以后 windows 桌面上发现 linux 过程的图形界面输入。
和远程桌面技术显示近程图形界面不同 (传递压缩的位图);XServer 和 XClient(也就是须要输入图形界面的 linux 过程) 之间通过 X 协定交谈(传递绘图指令),所以传输数据量更小,对网络带宽的需要低。
DISPLAY 环境变量指向本地 XServer 地址
首先咱们启动并登录一个装置了图形界面的 linux 服务器。使零碎为咱们筹备好本地图形环境。
而后,近程应用 SSH,近程登录服务器。应用 $ who
命令来查看,以后可用的图形环境
test :0 2022-04-14 09:47 (:0)
root pts/0 2022-04-14 09:47 (10.1.27.33)
留神,冒号前为空,示意 linux 本地的图形环境。咱们设置以后 SSH 连贯的 DISPLAY 属性指向 linux 本地图形环境。
$ export DISPLAY=":0"
应用 $ xhost
命令可查看 Xserver 的受权。
access control enabled, only authorized clients can connect
SI:localuser:root
SI:localuser:test
咱们凋谢所有用户可连贯:$ xhost +
access control disabled, clients can connect from any host
接下来,从新运行 java 程序:
$ export DISPLAY=":0"
$ xhost +
$ cd /opt
$ java -cp test.jar my.Test
这时候,察看 linux 本地登录用户的桌面,发现通过 SSH 运行的 Java 程序的界面被投射到 linux 本地用户桌面了。
无奈连贯 DISPLAY 的谬误
如果 DISPLAY 设定值和以后可用的图形环境不统一,那么就会产生相似上面的谬误。(我的项目在应用 VNC 登录时偶发上面谬误)
Can't connect to X11 window server using':2.0' as the value of the DISPLAY variable.
参考文档
- Linux 图形系统框架 与 X 协定
- 对于 VNC 的管制原理以及装置应用办法