工作中笔者接触到国产化达梦数据库,该数据库提供了图形化的管理工具manager
。Windows上安装的达梦打开管理工具很简单,直接在开始-->所有程序
中能找到manager
管理工具;而Linux上安装的达梦,需要在安装位置中找到tool
目录(例如全路径/home/dmdba/dmdbms/tool
)并执行./manager
,幸运的话就能够调出达梦manager图形化界面。
这里之所以说:幸运的话就能够调出达梦manager图形化界面,是因为连接同样的达梦服务器,有些时候在Linux SSH终端中能够打开成功manager管理工具,有些时候就会报错。比如说用putty
连达梦数据库服务器,执行./manager
就报错;用MobaXterm
连服务端执行./manager
就能够成功调出来。
实际上在没有理解
DISPLAY SERVER
之前是没有发现用不同的SSH客户端连接是造成打开达梦manager工具成功或者失败差异所在。这里提前说明下,用putty
和MobaXterm
分别打开达梦manager,前者失败后者成功的原因是后者自带X DISPLAY SERVER
并开启X Forwarding
功能。
现象就是:不同的SSH终端,有时候能打开manager图形化管理工具,有些时候就打开失败(后台报错)。到底是什么问题呢?
把问题抽象一下,实际上Linux上运行的达梦manager就是一个Linux gui程序,那么问题就是SSH终端怎么正确打开Linux gui程序?一番查询之后,发现是知识的盲区DISPLAY SERVER
。
Linux gui程序图形化展示和Window System
有什么关系呢?
Windows系统中打开图形化应用程序很简单,这是因为Win程序的图形化功能是写在内核中的(微软在DOC系统之后发现了图形化界面的巨大商业价值,后来开发的操作系统内核级别就支持图形化内容)。Linux(或者POSIX)系统要支持图形化界面程序,需要Window System
(Unix系统的哲学之一是:一个工具只做一件事并且把这件事做好,因此图形化显示在架构上也是解耦独立的)。
Window System
是一种实现了窗口、图标、菜单和像素点范式的gui。我们熟知的Unix操作系统大多使用X Window System
,苹果的OSX
系统使用Quartz Compositor
Window System。
注意这里的
Window System
不是Windows System
,和微软的windows系统没有关系。
Window System
核心是DISPLAY SERVER
(或者称为window server、compositor)。一个调用了DISPLAY SERVER
来显示图形化的程序称之为该DISPLAY SERVER
的客户端(client)。
既有client(调用DISPLAY SERVER
服务的gui程序),也有server(DISPLAY SERVER
),它们的交互就涉及到协议(protocol),这种协议就称为display server protocol。目前X Window System
的X DISPLAY SERVER
使用的协议就是X 11
(11表示的是版本)。
DISPLAY SERVER
的主要功能是协调操作系统、硬件和其他模块与gui程序之间的输入输出,它在图形化硬件上面提供一个抽象供更高级别的图形化接口(例如window manager
)使用。
Window System的设计是有层级的,这也体现了Unix系统的设计哲学。Window System
图形化调用架构如下:
如图所示,DISPLAY SERVER
是Window System
的核心所在。当你在Linux上打开一个gui程序的时候,该程序会调用DISPLAY SERVER
的图形化显示服务。这个时候DISPLAY SERVER
是服务端,而gui程序是客户端。这里和我们平时的理解有差异,一般我们认为服务端都是在远端,而客户端是在本地,这里DISPLAY SERVER
服务的调用是反过来(远端调用本地,也就是GUI程序调用DISPLAY SERVER
)。
那到底DISPLAY SERVER
在本地哪里呢?
可能是你本地Linux操作系统中自带的,也可能是你在Windows系统中手动安装的(Windows系统默认没有display server服务),还可能是ssh客户端工具(例如MobaXterm)内置提供的等等。但是总之,你想在本地启动Linux gui程序,本地一定是要有DISPLAY SERVER
服务的。
Linux gui程序是如何找DISPLAY SERVER
服务的呢?
在程序启动的环境变量中会查找DISPLAY
设置的服务地址。比如:
EXPORT DISPLAY=:0.0
表示调用本机DISPLAY SERVER
服务,服务的端口是127.0.0.1:6000
。
EXPORT DISPLAY=:10.0
表示调用本机DISPLAY SERVER
服务,服务的端口是127.0.0.1:6010
。
EXPORT DISPLAY=xx.26.18.37:3600.0
表示调用非本机(但可以在本地)DISPLAY SERVER
,服务的端口是xx.26.18.37:9600
。
这里说的“本机”指的是环境变量设置的主机,可能是本地主机,也可能是本地虚拟机,或者
ssh
远程的远端主机。“本地”指的是本地主机。
这里实际DISPLAY SERVER
服务监听的端口号是设置环境变量:
后第一个数字+6000
,正如上面:3600.0
实际服务监听的端口就是6000 + 3600 --> 9600
。配置完DISPLAY
环境变量之后,可以使用xhost +
来验证并禁用掉Access Control限制。
有些Linux服务端查看
echo $DISPLAY
设置的是:0.0
,但是并不能通过netstat -nalp |grep 60000
找打对应的X SERVER监听服务,这样的X SERVER只能够正常打开本地的gui程序,远程其他host并配置当前机器export DISPLAY=x.x.x.x:0.0
的DISPLAY属性并不能调通X SERVER服务。如果通过端口查看本地X服务在监听,则远程host配置本地X SERVER能够调用X SERVER服务并打开gui程序。
X11 Forwarding和DISPLAY环境变量设置是两个概念。DISPLAY是告诉你的环境去哪里调用X SERVER服务,而X11 Forwarding能够将本地配置的DISLAY SERVICE转发到Forwarding服务启动的X SERVER上。
使用MobaXterm
连接远程服务器时,该ssh
客户端会自动启动一个X DISPLAY SERVER
服务并开启X11 Forwarding
,保证你始终能正确打开Linux GUI程序。而putty
没有相应的功能,这也是解释了文章开头处说的为什么这两个ssh
客户端工具打开同样Linux GUI程序结果却不相同。
常见的DISPLAY SERVER
如下:
Windows系统的图形化是有内核程序支持的,因此Windows默认没有DISPLAY SERVER
。我们如果远程Linux机器并且在Win本地打开Linux gui程序,就需要安装DISPLAY SERVER,这里使用的DISPLAY SERVER
是X DISPLAY SERVER
或者称之为X SERVER
。
Windows经常用的X SERVER有XManager
、MobaXterm X SERVER
、XMing
等。MobaXterm
启动会默认在本地6000
端口(6000端口也是X协议:0的默认端口)启动一个X SERVER并开启X Forwarding功能。当在windows通过ssh工具远程Linux并启动gui程序的时候,内核会调用环境变量中配置的DISPLAY
服务绘制图形化界面,DISPLAY
的值写为IP:PORTOFFSET:0.0
的形式,会访问IP:6000+PORTOFFSET
的X服务。我们试验一下:
远程一个安装有完整JDK的虚拟机,打开jvisualvm
,如果没有DISPLAY
环境变量设置,会报错:
在Windows10系统上安装VcXsrv Windows X Server,,安装后打开并配置display num
为3600
、Access Control
为disable
,如图:
在虚拟机上设置export DISPLAY=$HOST:3600.0
,重新打开jvisualvm
:
这时候就能够成功打开jvisualvm
这个linux的gui程序了。
这里的
$HOST
是安装VcXsrv的Windows的IP,保证9600
端口和虚拟机是通的。这里的DISPLAY NUM
这个端口是可以自定义设置的,这里设置为3600
的原因是本机的9600
端口和虚拟机是通的。
Unix like系统的gui程序图形化展示需要Window System
服务的支持,服务的核心是DISPLAY SERVER
。当图形化gui程序打开的时候,DISPLAY SERVER
作为本地被调用服务端,而gui程序作为本地或远端客户端调用方存在,二者通过display protocol
进行通信。gui程序通过程序启动的环境变量DISPLAY
获取要调用的DISPLAY SERVER
地址,该默认值是:0.0
,表示调用本机的DISPLAY SERVER
。
需要注意:
DISPLAY SERVER
服务监听的端口之间必须是通的(如果有防火墙限制,服务调用会失败)。export DISPALY=x.x.x.x
之后,启动gui程序报错缺少*.so
类库,则可能是类库版本有差异,在/lib
或者/lib64
找到名称类似版本不同的类库创建需要类库版本的软连接即可。命令:ln -s /lib64/libxxx.so.6 /lib64/libxxx.so
将/lib64/libxxx.so.6
创建一个软链接为/lib64/libxxx.so
。