探究X Window System运行原理与启动过程

╰半橙微兮° 2021-11-04 20:36 478阅读 0赞

探究X Window System运行原理与启动过程

作者:xdkui

  1. 第一次在Debian下装XFree86startx启动了twm,装了gnome startx启动了gnome环境,为什么?装gnome 时修改了什么文件以及X环境是怎么起来的?本来是想搞清这几个文题开始研究这个题目的,没想到还学到了很多别的东西^\_^本文主要说明X Window System的基本运行原理,其启动过程,及常见的跨网络运行X Window System
  2. 一) 基本运行原理
  3. X Window System采用C/S结构,但和我们常见的C/S不同。常见的C/S结构中,称提供服务的一方为server,即服务器端(如HTTP服务,FTP服务等),使用服务的称为client,即客户端。但在X Window System中,client是执行程序的一方,在上面执行各种X程序,而server则是负责显示client运行程序的窗口的一方。
  4. X Window System的组成可以分为X serverX clientX protocol三部分。X server主要控制输入输出,维护字体,颜色等相关资源。它接受输入设备的输入信息并传递给X clientX client将这些信息处理后所返回的信息,也由X server负责输出到输出设备(即我们所见的显示器)上。X server传递给X client的信息称为Event,主要是键盘鼠标输入和窗口状态的信息。X client传递给X server的信息则称为Request,主要是要求X server建立窗口,更改窗口大小位置或在窗口上绘图输出文字等。X client主要是完成应用程序计算处理的部分,并不接受用户的输入信息,输入信息都是输入给X server,然后由X serverEvent的形式传递给X client(这里感觉类似Windows的消息机制,系统接收到用户的输入信息,然后以消息的形式传递给窗口,再由窗口的消息处理过程处理)。X client对收到的Event进行相应的处理后,如果需要输出到屏幕上或更改画面的外观等,则发出RequestX server,由X server负责显示。
  5. 常见的情况是X serverX client都在同一台电脑上运行,但他们也可分别位于网络上不同的电脑上。在X Window System中,X client是与硬件无关的,它并不关心你使用的是什么显卡什么显示器什么键盘鼠标,这些只与X server相关。我们平常安装完XFree86后运行xf86configxf86cfg进行的配置实际上只是与X server有关,可以说就是配置X server吧,不配置照样可以运行X client程序(如:xeyes -display xserver:0就可以在xserver这台机器上的0号屏幕(屏幕编号displaynumber0)上显示那对大眼睛了)。
  6. X protocol就是X serverX client之间通信的协议了。X protocol支持现在常用的网络通信协议。我只能测试TCP/IP,可以看到X server侦听在tcp 6000端口上。那X protocol就是位于运输层以上了,应该属于应用层吧?。
  7. 总结下运行过程吧:
  8. (1) 用户通过鼠标键盘对X server下达操作命令
  9. (2) X server利用Event传递用户操作信息给X client
  10. (3) X client进行程序运算
  11. (4) X client利用Request传回所要显示的结果
  12. (5) X server将结果显示在屏幕上
  13. 二) 启动过程
  14. 我们从控制台进入X一般是用startx命令。下面就从startx分析起。首先man startxman xinit可以看到staratxxinit的使用方法:
  15. startx \[\[client\] options .....\] \[-- \[server\] options ....\]
  16. xinit \[\[client\] options \] \[-- \[server\] \[display\] options\]
  17. 把上面\[client\]\[server\]分别称为client程序和server程序。man手册里写明其必须以/或者./开头。
  18. 下面看看startx这个脚本,中文为我加的注释,这个脚本是安装x-window-system-core后得到的,都是XFree86,不同发行版的linux里该脚本应该大同小异:
  19. \#!/bin/sh
  20. userclientrc=$HOME/.xinitrc \#用户的client定义文件
  21. userserverrc=$HOME/.xserverrc \#用户的server定义文件
  22. sysclientrc=/usr/X11R6/lib/X11/xinit/xinitrc \#系统的client
  23. sysserverrc=/usr/X11R6/lib/X11/xinit/xserverrc \#系统的server
  24. defaultclient=/usr/X11R6/bin/xterm \#默认的client程序
  25. defaultserver=/usr/X11R6/bin/X \#默认的server程序
  26. defaultclientargs="" \#下面定义了clientserver的参数变量
  27. defaultserverargs=""
  28. clientargs=""
  29. serverargs=""
  30. \#如果用户client文件存在则使用用户文件里定义的client,否则使用系统定义的client
  31. if \[ -f $userclientrc \]; then
  32. defaultclientargs=$userclientrc
  33. elif \[ -f $sysclientrc \]; then
  34. defaultclientargs=$sysclientrc
  35. fi
  36. \#如果用户server文件存在则使用用户文件里定义的server,否则使用系统定义的server
  37. if \[ -f $userserverrc \]; then
  38. defaultserverargs=$userserverrc
  39. elif \[ -f $sysserverrc \]; then
  40. defaultserverargs=$sysserverrc
  41. fi
  42. \#下面循环处理clientserver的参数
  43. whoseargs="client"
  44. while \[ x"" != x \]; do \#若第一个参数为空,退出循环
  45. case "" in
  46. \# '' required to prevent cpp from treating "/\*" as a C comment.
  47. /''\*|./''\*) \#如果是/\*或者./\*形式(xinit程序要求其参数里的client程序和server程序必须以/或./开头,否则会被视为client程序和server程序的参数,见man xinit)
  48. if \[ "$whoseargs" = "client" \]; then \#如果当前是在处理client的参数
  49. if \[ x"$clientargs" = x \]; then \#如果clientargs为空,则赋值给client变量,也即上面\#startx使用方法里的\[client\]参数
  50. client=""
  51. else
  52. clientargs="$clientargs " \#否则clientargs赋值为$clientargs ,即上面\#startx使用\#方法里的options参数
  53. fi
  54. else \#当前在处理server的参数,代码的含义同上
  55. if \[ x"$serverargs" = x \]; then
  56. server=""
  57. else
  58. serverargs="$serverargs "
  59. fi
  60. fi
  61. ;;
  62. --)\#如果为--,则表示开始处理server的参数,--为clientserver参数的分界
  63. whoseargs="server"
  64. ;;
  65. \*)
  66. if \[ "$whoseargs" = "client" \]; then \#处理给client程序的参数
  67. clientargs="$clientargs "
  68. else \#处理给server程序的参数
  69. \# display must be the FIRST server argument
  70. \#屏幕编号必须为第一个给server程序的参数,以的形式(x为数字),这可从上面startxxinit 的使用
  71. \#方法的区别看出,xinit多了个\[display\],这里即过滤出这个\[display\]。试试看这两个命令:
  72. \#xinit /usr/bin/X11/xeyes -display localhost:1 -- /usr/bin/X11/X :1 -dpi 70&
  73. \#xinit /usr/bin/X11/xeyes -display localhost:1 -- /usr/bin/X11/X -dpi 70 :1&
  74. \#即可看出不把屏幕编号作为第一个server参数的后果
  75. if \[ x"$serverargs" = x \] && expr "" : ':\[0-9\]\[0-9\]\*$' > /dev/null 2>&1; then
  76. display=""
  77. else \#处理屏幕编号以外的参数
  78. serverargs="$serverargs "
  79. fi
  80. fi
  81. ;;
  82. esac
  83. shift \#所有参数左移一次
  84. done
  85. \# process client arguments
  86. if \[ x"$client" = x \]; then \#如果client程序为空
  87. \# if no client arguments either, use rc file instead
  88. if \[ x"$clientargs" = x \]; then \#clientargs为空,赋值$defaultclientargsclient程序
  89. client="$defaultclientargs"
  90. else
  91. client=$defaultclient \#使用默认的client程序
  92. fi
  93. fi
  94. \# process server arguments处理server参数,同上
  95. if \[ x"$server" = x \]; then
  96. \# if no server arguments or display either, use rc file instead
  97. if \[ x"$serverargs" = x -a x"$display" = x \]; then
  98. server="$defaultserverargs"
  99. else
  100. server=$defaultserver
  101. fi
  102. fi
  103. \#…………省略授权代码若干
  104. xinit $client $clientargs -- $server $display $serverargs \#把处理过的参数交由xinit程序处理
  105. \#…………
  106. 由上面代码可以得出startx主要是置X clientX server所在的位置,并处理相关参数,最后交给xinit处理。可以看出startx 设置X client的位置是先搜寻$HOME/.xinitrc,然后是/etc/X11/xinit/xinitrc;设置X server的位置是先搜寻$HOME/.xserverrc,然后是/etc/X11/xinit/xserverrc。这就解释了我们平常为什么说启动X Window时用户目录下的.xinitrc和.xserverrc文件优先级要高。所以我们用startx命令启动X时,如果用户目录存在.xinitrc和.xserverrc文件,则实际上等价于命令xinit $HOME/.xinitrc -- $HOME/.xserverrc 。如果用户目录不存在那两个文件,则等价于xinit /usr/X11R6/lib/X11/xinit/xinitrc -- /usr/X11R6/lib/X11/xinit/xserver。别的情况类推。
  107. 至于xinit,则根据startx传过来的参数启动X server,成功后根据xinitrc启动X client
  108. 以上即为X Window System的启动过程,startx只是负责一些参数传递,真正的X启动由xinit实现。实际上可以分为启动X server和启动X client两部分。下面在用户目录下构造.xinitrc(即X client)和.xserverrc(即X server)文件。在.xserverrc里写入/usr/bin/X11/X :1。.xinitrc里写入/usr/bin/X11/xeyes -display localhost:1。这就是最简单的X server + X client了,只不过把屏幕编号从默认的0改为了1,这里X server即是/usr/bin/X11/X 程序,X client即是/usr/bin/X11/xeyes 程序。
  109. 总结下单机用startx启动过程吧:
  110. (1) startxX clientX server的位置,处理参数并调用xinit
  111. (2) xinit根据传过来的参数启动X server,成功后呼叫X client
  112. (3) 根据xinitrc设置相关资源,启动窗口管理器,输入法和其他应用程序等X client程序。
  113. 但还未搞清楚gnome是怎么起来的!gnome当然属于X client了,看上面启动过程第(3)步。
  114. 这里分两种情况看吧,第一种是用系统的xinitrc文件。看/etc/X11/xinit/xinitrc文件(我的sargex-window-system-coregnome-core),里面只包含了. /etc/X11/Xsession一句话。接着看/etc/X11/Xsession这个脚本,只看关键部分吧。最后面有:
  115. SESSIONFILES=$(run\_parts $SYSSESSIONDIR)
  116. if \[ -n "$SESSIONFILES" \]; then
  117. for SESSIONFILE in $SESSIONFILES; do
  118. . $SESSIONFILE
  119. done
  120. fi
  121. exit 0
  122. 接着看run\_parts(),位于本文件中间:
  123. run\_parts () \{
  124. \# until run-parts --noexec is implemented
  125. if \[ -z "" \]; then
  126. internal\_errormsg "run\_parts() called without an argument."
  127. fi
  128. if \[ ! -d "" \]; then
  129. internal\_errormsg "run\_parts() called, but "" does not exist or is"
  130. "not a directory."
  131. fi
  132. for F in $(ls ); do
  133. if expr "$F" : '\[\[:alnum:\]\_-\]+$' > /dev/null 2>&1; then
  134. if \[ -f "/$F" \]; then
  135. echo "/$F"
  136. fi
  137. fi
  138. done
  139. \}
  140. 大概意思就是run\_parts () $SYSSESSIONDIR目录下的文件名取出来赋值给$SESSIONFILES,然后循环运行该目录下的文件。看看该目录,即/etc/X11/Xsession.d目录,可以看到几个以数字开头的文件,实际上这些数值就表示了这几个文件被运行的优先级,数字小的优先级高,因为在上面的run\_parts () 里是用ls命令显示该目录下的文件,所以前面数字小的被ls时显示在前面,所以被
  141. for SESSIONFILE in $SESSIONFILES; do
  142. . $SESSIONFILE
  143. done
  144. 这个for循环执行时也先被执行。看到/etc/X11/Xsession.d目录下有个55gnome-session\_gnomerc文件,里面提到了STARTUP变量。然后运行:
  145. [xdkui@Debian:/etc/X11/Xsession.d$][xdkui_Debian_etc_X11_Xsession.d] grep STARTUP \*
  146. 看到50xfree86-common\_determine-startup文件。里面有
  147. if \[ -z "$STARTUP" \]; then
  148. if \[ -x /usr/bin/x-session-manager \]; then
  149. STARTUP=x-session-manager
  150. elif \[ -x /usr/bin/x-window-manager \]; then
  151. STARTUP=x-window-manager
  152. elif \[ -x /usr/bin/x-terminal-emulator \]; then
  153. STARTUP=x-terminal-emulator
  154. fi
  155. fi
  156. 即设置启动程序,实际上设置STARTUP变量,如果以上程序都没有找到,则会报错退出,即X环境没有被启动。再运行
  157. [xdkui@Debian:/etc/X11/Xsession.d$][xdkui_Debian_etc_X11_Xsession.d] grep STARTUP \*
  158. 看到优先级最低也即最后被运行的99xfree86-common\_start文件,里面只有一句话:
  159. exec $STARTUP
  160. 好了,到这里就启动我们的X client了,终于完了^\_^。总结下这第一种方式的启动过程,简单的说就是依次顺序查找/usr/bin/x-session-manager x-window-manager,/usr/bin/x-terminal-emulator 这三个文件。如果存在则启动之,也即X client。如果三个都不存在则报错退出了。看/usr/bin/x-session-manager文件可以看到是个符号连接,最终连接到/usr/bin/gnome-session,也就是gnome 了。至于我们在gnome 启动时可能会设置启动输入法等程序,那就归gnome-session管了,也就不再分析了。可以试着把/usr/bin/x-session-manager 改为指向xfce4-session(如果安装了的话) ,再startx就会启动xfce4环境了。大概RedHatswitchdesk工具就是改这个连接实现的吧?。或者删掉/usr/bin/x-session-manager ,再startx,只启动了/usr/bin/x-window-manager 所指向的window manager了吧,我这里是blackbox
  161. 下面看第二种情况,即用户目录的xinitrc文件$HOME/.xinitrc。对比hiweed-debian-desktop\_0.55\_i386,存在$HOME/.xinitrc文件,在里面有exec xfce4-session。故其X client可以说最主要的x-session-manger是从$HOME/.xinitrc启动的。也就不会经过上面第一种情况的执行过程了。
  162. 终于把gnome(或者说x-session-manger)的启动过程弄明白了,下面说点别的吧。xinit程序同时启动X serverX client,这在单机上还可。要是位于网络上的两台电脑分别是clientserver,则xinit就无能为力了。这时就得靠纯“手工”来启动X了。下面简单的“手工”启动X serverX client:在CUI模式下运行命令:
  163. [xdkui@Debian:~$X][xdkui_Debian_X] :1&
  164. 看到了一个灰色的全屏幕和一个鼠标指针,这就是X server了,其屏幕编号为1。下面构造X client,按Ctrl+Alt+F1回到刚才的CUI(Ctrl+Alt+F7对应本机的第一个启动的X serverCtrl+Alt+F8对应第二个,有人说F7对应屏幕编号为0X server实际上是不对的,如果第一个启动的屏幕编号为1,第二个启动的编号为0,则F7对应1屏幕,F8对应0屏幕),运行命令:xdkui@Debian:~$xeyes -display localhost:1&
  165. 然后按Ctrl+Alt+F7,看到我们的X client也就是xeyes了吧。再回到CUI,运行
  166. [xdkui@Debian:~$X][xdkui_Debian_X]&
  167. 开启一个屏幕编号0X serverCUI下再运行
  168. [xdkui@Debian:~$xterm][xdkui_Debian_xterm]&
  169. 这时Ctrl+Alt+F7对应屏幕编号1;而F8对应屏幕编号0,且其X clientxterm。先退出上面的两个X server,下面复杂点手动启动我们的gnome吧,首先
  170. [xdkui@Debian:~$X][xdkui_Debian_X]&
  171. 然后
  172. [xdkui@Debian:~$gnome-session][xdkui_Debian_gnome-session]
  173. 看到的就和用startx 启动的X一样了,这时X serverX这个程序,X clientgnome-session及其启动的窗口管理器等程序。看到这里感觉xinit用处并不大(??不知是否正确),简单的脚本就可以实现。本来想把xinit反汇编了分析下,可懒得搞了^\_^这是位于本机的情况,对于X serverX client位于不同主机的情况见下面本文第三部分。
  174. 个人感觉对于X Window System,搞清楚X serverX client关系很重要。一般X server很简单,就是/usr/bin/X11/X程序;X client则花样繁多,从高级的CDE,GNOME,KDE,到低级一点的只有twm,Window Makerblackbox等窗口管理器,再到最简陋的只有xterm,rxvt,xeyes等单个x程序。正是由于X client的各种搭配,使得我们的X Window System看起来多样化。这可能也是X Window System最大的卖点之一吧 ^\_^
  175. 三) 跨网络运行X Window System
  176. 一般用来做服务器的系统(Linux,FreeBSD,Solaris等等)都不会装X server,甚至很多都没有显示器。这样可以在这些系统里安装简单的X client,以GUI的方式远程显示在管理员们所坐的X server里。我们实验室用FreeBSD做网关,提供WWW,FTP服务,一般在管理员的本地机器起个X server,然后sshtelnet上网关运行X client程序显示在本地显示器上,当然,也可用XDMCP(X Display Manager Control Protocol),man xsession里提到/etc/X11/Xsession一般被startx(我的/etc/X11/xinit/xinitrc里调用Xsession脚本)或display manager调用,但有的display manager只调用Xsession而不是xinitrc,故为了startxdisplay manager两种方式下都可正常启动GUI,最好把X client启动的程序放在Xsession文件里。远程运行X client程序需要设置DISPLAY环境变量,设置为 主机名称:屏幕编号(如192.168.1.2:0,则表示X server192.168.1.2这台机器上的0号屏幕);或是给X client程序加个—display参数。由于条件限制,只测试了位于TCP/IP网络环境,X server192.168.1.2X client192.168.1.1
  177. 1) Windows系统做X server
  178. a) sshtelnet方式
  179. Windows下面的X server软件有很多种,我这里使用X-win32。在Windows里运行X-win32程序,则相当于本地机器是个X server。远程登录上Debian(我这里是用VMware仿真网络环境,直接进虚拟机即可^\_^),运行:
  180. [xdkui@xclient:~$export][xdkui_xclient_export] DISPLAY=192.168.1.2:0
  181. [xdkui@xclient:~$xterm][xdkui_xclient_xterm]&
  182. 这时即在Windows里的X server里看到了xterm了,至于X client还运行什么程序就看你的需要了,文件管理器阿,资源查看器等。当然,这里X-win32要设置好授权,好像默认是禁止接入控制,即任何X client都可使用这个X server
  183. b) XDMCP方式
  184. 常见的Display Managerxdm,gdm,kdm等。我这里使用的是gdm。需要修改gdm的配置文件/etc/X11/gdm/gdm.conf,修改\[xdmcp\]段的Enabletrue,使得可以远程登录,在X client运行gdm
  185. X-win32里建一个XDMCPsession,查询方式,填入IP为运行gdm的机器地址。连接,即可看到登录界面,下面的就不用说了,享受吧
  186. 2) LinuxLinux互联
  187. a) sshtelnet方式
  188. linux本地起个X server,需要注意授权问题,建立文件/etc/X0.hosts,填入X clientIP192.168.1.1,其中X0.hosts表示本地第0个屏幕允许连接的X client地址,建立X1.hosts文件则是本地第1个屏幕允许连接的X client地址,以此类推,man xserver里有。运行
  189. [xdkui@xserver:~$X][xdkui_xserver_X]&
  190. 运行该程序时别加-nolisten参数,否则不会在网络上侦听。
  191. 这个时候Ctrl+Alt+F7X server,返回Ctrl+Alt+F1还可以sshX client机器上。
  192. 然后登录上X client,运行
  193. [xdkui@xclient:~$xterm][xdkui_xclient_xterm] display 192.168.1.2:0
  194. 即可在本地的X server里看到xterm了,如果有的话,还可把gnome-session也显示在本地来。同样可以在linux里的VMware里做这个测试,需要用点手腕了^\_^见下
  195. b) XDMCP方式
  196. 在我们的X client里运行gdm(别忘了修改gdm.conf),然后在本地X serverCUI下面运行X -query 192.168.1.1(X clientgdm机器的地址)。可以看到登录界面了吧。
  197. 我是在linux里的VMware里做的测试,说说所用的手腕吧。在Ctrl+Alt+F1CUI下正常运行startx&启动GUI,这时Ctrl+Alt+F7即为我的X serverX client启动的gnome,然后在这里运行VMware打开Debian虚拟机,并运行gdm。然后回到Ctrl+Alt+F1,运行X :1 -query 192.168.1.1。看到登录界面了吧。这时Ctrl+Alt+F7为我的0号屏幕,里面运行了虚拟机。Ctrl+Alt+F81号屏幕,在远程GUI登录X client。相当于我在本地起了两个X server
  198. X Window System设计的真是相当神奇,使用方法更是眼花缭乱。佩服………

转载于:https://www.cnblogs.com/F4ncy/archive/2005/02/12/103959.html

发表评论

表情:
评论列表 (有 0 条评论,478人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Windows启动原理

    Windows的启动过程极其额复杂。以Windows XP为例,它过程的启动大致分为5个步骤。 第1步 预启动:首先电脑通电自检,并由BIOS(基本输入输出系统)扫描硬件并完

    相关 Windows启动过程详解

    我们每天都在和Windows打交道,很多人可能每天都要面对多次Windows的启动过程,可是您知道在Windows的启动过程背后,隐藏着什么秘密吗?在这一系列过程中都用到了哪些