X window system(X11)

Published: by Creative Commons Licence

  • Categories:

自从17年将开发主力系统切换为Linux之后,遇到了很多和X11相关的问题,因此就抽时间梳理了一下相关的内容。

X11 是一个协议,它规定了XserverXclient通信的方式,给GUI程序提供了使用显示器,显卡,键盘,鼠标等设备的能力。

Xserver 是实现了X11服务端协议的进程,比如 Xorg 程序,它负责维护一个 Display(=显示器+鼠标+键盘+显卡),允许 Xclient 程序使用这个 Display。它把它维护的 Display 包装成服务提供给 Xclient 程序使用,所以它是 server 端。既然是 server 端,它当然允许远程任意设备上的 Xclient 程序来连接它,使用它提供的显示服务。比如运行在 A 设备上的 firefox 进程,可以连接 B 设备的 Xserver,从而将界面显示在 B 设备上。

Xclient 是能够使用 X11 协议和 Xserver 通信的程序,比如常见的所有 Linux 上的 GUI 程序,firefox,chrome等。

在 AB 两台设备上使用 X11 的示意图如下,图上显示在 A 电脑上启动 firefox 程序,其界面显示在 B 电脑上。这里用两台电脑做演示是为了让你体会 程序的界面和程序的执行是独立的,当 A,B 合二为一的时候,原理不变。

x11

在这个例子中,A 电脑提供了 firefox 程序运行所需要的 CPU,内存等资源,B 电脑提供了 firefox 程序界面需要的显示服务,包括显示器,键盘,鼠标。

X11支持扩展,其中最重要的一个扩展是 GLX 扩展,它允许X11客户端自行渲染客户端的内容(比如使用OpenGL),而不用将全部的渲染都经过X服务器。也是因为有了这个扩展,Linux上的应用才能使用GPU硬件加速的UI渲染。

手动启动Xserver

发行版系统的Xserver一般是由DM来启动的,可以查看相关DM的说明文档了解详细信息。

关于在发行版中 Xserver 的启动流程可以参考 Linux 桌面GUI及其启动流程

单独的Xserver启动后你会看到一个全黑的屏幕,因为没有任何Xcient程序运行,所有的界面都需要Xclient程序来提供,发行版中的整个DE界面都是Xclient程序。

手动启动Xserver的方式由很多,下面一一介绍。

手动最直接启动Xserver的方法是直接使用 X 命令,下面是一个例子。

在 10 号本地display中启动X,显示在vt8中,最后一个Xclient退出后自动结束Xserver,2秒后在10号display中显示xterm程序,命令如下:

sudo X :10 -terminate vt8 & sleep 2 ; DISPLAY=:10 xterm

通过xinit程序启动Xserver:

sudo xinit /usr/bin/xterm -display :10 -- -terminate vt8 :10

注意:通过xinit 启动的Xclient默认在0号display显示。

如果xinit不添加任何参数,则会查找~目录下的.xinitrc脚本文件,具体查看man xinit。

通过startx脚本启动Xserver:

sudo startx /usr/bin/xterm -- -terminate vt8 :10

注意:通过startx启动的Xclient会在新启动的display中的显示。

startx 不一定要在sudo权限下运行,他可以处理权限相关内容,参见下文的 xauth

启动一个允许远程 Xclient 连接的 Xserver

首先使用 Ctrl+Shift+F1 切换到 tty1

然后运行以下命令:

startx /usr/bin/mate-session -- X :1 vt5 -listen tcp -terminate

以上命令中的 -- 之前的参数是Xclient的参数, -- 之后的参数是传给Xserver的参数。

然后在任意终端中运行xhost来添加连接权限:

DISPLAY=:1 xhost +

然后就可以在任意设备上运行Xclient程序并且显示在本机(192.168.1.4)上:

DISPLAY=192.168.1.4:1  firefox

为了方便调试XClient和Xserver,可以使用Xnest命令来启动一个嵌套在当前Xserver中的虚拟Xserver,它会把其中运行的所有程序的X请求转发到当前的Xserver中:

startx /usr/bin/xterm -- /usr/bin/Xnest :10 -terminate

类似的功能也可以使用Xephyr程序。

Xorg的启动日志在 ~/.local/share/xorg/Xorg.<Display>.log 文件中。 启动session的配置在 /user/share/xsession/* 目录下。 X11的配置在 /etc/X11/* 目录下。

任何的XServer启动后都会在 /tmp/.X11-***/ 目录下创建一个相应display的文件,记录了Xserver的pid。同时会有一个/tmp/X*** 的目录记录相应display的信息。可以通过这些来查看当前系统上启动的所有Xserver。

在X11中,所有选中的内容,都可以通过单击中键粘贴。

Xorg 提供的管理工具:

  • xdpyinfo 查看Display的信息。
  • xwininfo 查看窗口信息,包括窗口树。
  • xset 查看及设置Xserver的信息。
  • xkill 结束一个Xclient。
  • xwd 截图。
  • xwud 查看截图.
  • xrefresh 重绘所有Xclient。
  • xrandr --query 查看当前的屏幕信息。
  • xhost 用来设置当前的Xserver是否允许远程的xclient连接。如果要允许本机display 1显示远程的Xclient,则执行下面的命令,注意这会关闭在display1上连接认证,从而允许所有的设备连接display1。

    DISPLAY=:1 xhost +
    

以下工具常用来辅助X11程序的开发及测试,他们都“实现”了X11协议,可以理解为一个Xserver。

  • Xnest 创建一个窗口作为DISPLAY,它把其上运行的Xclient对Xserver的请求重定向到本机已有的Xserver上。
  • Xephyr 类似 Xnest,但是不进行重定向,它自己实现了Xserver,会将Xclient显示在一个窗口中。

Xvnc

同时提供Xservervnc server,但是其中的Xserver不和物理Display关联,只能通过vnc client来查看。

Xvnc :1 -rfbauth <passwd-file> 在Display1上启动Xvnc,并指定密钥文件,其他端可以通过 gvncviewer <ip>:1 来连接,可以看到系统登陆界面以及正常登陆DE。

X11vnc

提供 vnc server,当vncclient连接后可以看到本机的X11画面,并允许远程控制;同WinVNC;

x11vnc -display :1 在Display1上等待vnc连接,客户端使用gvncviewer <ip>:1 来连接,可以看到系统当前Display0的画面。

Xvfb 纯软件的 Xserver,不和物理Display关联,通过xwd可以截图查看内容。

xauth

X提供了 MIT-MAGICCOOKIE-1 协议用来实现基于 ~/.Xauthority 的安全认证。

为了让这种机制能够用于认证远程主机,又提供了 XDM-AUTHORIZATION-1 协议,主要是为了避免要把 MAGICCOOKIE 进行网络传输才能认证远程主机,从而提高安全性。

xauth 命令可以用于操作.Xauthority文件;

xcookie 可以用于生成cookie字符串;

~/.Xauthority 文件(DM可能使用不同文件,可以通过Xorg的启动参数查看)记录了连接当前Xserver可以使用的cookie。在启动Xserver的时候通过 -auth 参数可以指定该文件的位置,只要指定了该文件则Xserver启动时就不需要是root权限。

~/.Xauthority 文件同时也是Xclient连接Xserver时需要使用的文件,它会获取其中的cookie用于认证。(它的位置也可以改变)

所以对于Xclient只要在本机中的~/.Xauthority文件中写入了有了远程Xserver对应Xauthority文件中的cookie值,本机的Xclient就可以连接远程的Xserver了,这会忽略xhost安全机制。

XDMCP(X Display Manager Control Protocol)

XDMCP 是一个独立于X11的协议,它用于支持用户登陆一个远程的session,可以配合Xephyr作为远程登陆来使用。

一般来讲DM作为XDMCPserver,而Xorg作为XDMCP的client,因此使用Xserver的-query参数可以让X连接远程的session,可以显示远程的登陆界面,远程的WM,DE等。

大多数的DM默认这个功能是被关闭的,要配置DM开启XDMCPserver才能用。

lightDM

lightDM 是目前Ubuntu,Manjaro-mate等系统默认使用的DM。

lightdm 配置文件的路径:

/usr/share/lightdm/
/etc/lightdm/

配置文件可以分功能分文件写,也可以写在一个文件中。 日志文件在 /var/log/lightdm。 一般 lightdm 都是被init系统作为一个系统服务启动,可以通过service或者systemctl命令来控制lightdm服务的启停。

这里有一份lightdm支持的配置选项列表:

https://askubuntu.com/questions/140471/is-there-a-list-of-all-the-possible-configuration-options-for-lightdm

其中xserver-allow-tcp用于控制是否允许Xserver以监听tcp连接;

[XDMCPServer] 节点用于控制XDMCPServer;

[VNCServer] 节点用于控制VNCServer;

ArchWiki上的文档也值得一看: https://wiki.archlinux.org/index.php/LightDM

Display

display: 包括鼠标,键盘,显卡,显示器等设备的一个集合,每一个display都最多对应一个Xserver,Xclient可以连接到这些display,display的唯一标识称为 display specification(displayspec),格式如下:

host:display-number[.screen]

比如:

:0 使用本地unix/socket方式连接的 0 号 display.

localhost:2 使用tcp连接的本地 2 号display.

1.2.3.34:5.0 使用tcp连接的IP为1.2.3.34机器上的 5 号display 的 0 号 screen.

Xclient程序在启动的时候可以通过DISPLAY环境变量来指定要连接的display,比如:

DISPLAY=:3 firefox 在本地3号display上显示程序firefox。

每一个Xserver启动后都会占用一个TCP端口,用来监听客户端的连接,监听端口号为 6000+display,比如,:0 号display的TCP端口号为6000+0=6000,以此类推。

X11之所以还在v11,可能是因为它提供了较好的扩展机制,很多新功能都通过扩展实现了。

由于显卡相对于其他硬件太过复杂,几乎不可能定义一套通用的接口以供应用程序使用,因此,Linux给与Xserver完全管控显卡的能力,虽然部分显卡驱动提供一些内核模块来配合Xserver的工作。

Virtual Terminals(VT)

Linux提供virtual terminal(virtual console)的机制,用来实现虚拟显卡。

每一个display同一时间只能和一个VT关联,每一个VT可以处于不同的模式,比如有的处于字符界面,有的处于GUI界面。用Ctrl+Alt+Fx来切换VT,默认情况下Linux开机后就创建7个被占用的VT,VT1-VT7,默认的Xorg使用VT7。一般系统一共会创建63个VT,可以 ls /dev/ttyN 查看,每一个ttyN都是一个VT。

如果VT处于字符界面,可以通过 Alt+Fx 来切换到其他VT,或者通过 Alt+LeftArrow 来切换到上一个VT。

也可以通过chvt或者switchto命令来用命令切换VT。

使用tty命令可以查看当前使用的tty。

使用 openvt 命令可以在其他VT中运行指定程序。tty8-tty63默认情况下不会运行任何程序,因此切换过去是空白的字符界面。VT8默认是第一个没有被占用的终端(错误!)。init程序负责配置tty1-tty7,一般使用agetty作为字符界面的登陆程序。

/dev/tty0/dev/tty/dev/console指向当前tty,跟随当前tty变化而变化。通过ps命令可以查看进程所属的tty。

runlevel

可以通过内核参数来设定init启动的runlevel级别,也可以通过执行init x 来切换到指定的runlevel。一般情况下用户所在的runlevel是5


参考文档: