使用远端xserver

约定

下文中,GUI程序所在地称为本地端,xserver所在地称为远端。

连接

本地端如果有sshd,并配置开启X11转发;远端开启xserver后,给ssh也配置上X11转发,这样ssh session创建完成后,sshd会创建一个本地端的代理xserver,通过ssh的加密传输来代理到远端的xserver。

期间ssh还负责给session设置$DISPLAY,给用户主目录的.Xauthority添加cookie以完成验证权限等操作。

问题是ssh加密传输在传输x的数据的时候,速度太慢了,cpu占用也高;可以通过压缩传输以及更换比较快的加密算法来改善,但是效果依然差强人意。

 

所以还是在本地端自己设置DISPLAY为“远端IP:0.0”并启动GUI客户端速度最快。

这个可以做个快捷启动。在本地端做一个这个脚本:

!/usr/bin/bash
# use plink.exe together with a remote X server to execute this script
# make sure a proxy DISPLAY and .Xauthority cookie is ready here
# make the remote server accept all future client request from this end
xhost +192.168.111.11
# reset the direct DISPLAY to make it work smoothly
DISPLAY=192.168.111.1:0.0 /usr/bin/konsole
# now this script exits, so does plink.exe

 依然用ssh的X11转发来简历代理DISPLAY,只是这个代理只做一件事,就是设置远端的xserver的权限,以便后续的konsole的顺利启动。

 

字体

本地端xlsfonts命令会直接连接$DISPLAY的xserver,并列出来该xserver上的传统字体,这个行为就跟用xset来配置远端xserver是一样的。

因此当你的GUI程序使用的是传统的xserver字体系统(现在很少了,不过估计xterm应该是),那么就需要在远端的xserver上安装字体并生成fonts.dir和fonts.scale,让xserver启动的时候加载它们。

 

当你的GUI程序是用的font-config字体系统时(现在主流的qt和gtk应用应该都是,例如konsole),那么需要在本地端安装字体,并且用fc-cache扫描它们,这样GUI程序启动之后会渲染好了发送到$DISPLAY的xserver那里显示出来。

 

后记

后来做了一个ruby脚本,在xserver(cygwin的XWin最稳定,用XWin -multiwindow -listen tcp启动)端运行后,通过plink.exe来启动xclient端的konsole在xserver端显示。

xserver = '192.168.111.1'
xclient = '192.168.111.11'

rd, wr = IO.pipe
pid = Process.spawn(
  "C:\\opt\\putty\\plink.exe",
  "-ssh", "-batch", "-i", "C:\\opt\\putty\\id_rsa.ppk", "yuqing@#{xclient}", "ruby",
  :in => rd)
wr.write <<-EOBlock
  # make sure a proxy DISPLAY and .Xauthority cookie is ready
  puts 'Force #{xserver} to accept all future client request from #{xclient}...'
  if !system('xhost +#{xclient}')
    exit 1
  end
  puts 'Use #{xserver} as direct DISPLAY to start GUI client...'
  pid = Process.spawn(
    {'DISPLAY' => '#{xserver}:0.0'},
    '/usr/bin/konsole', '--nofork',
    [:in, :out, :err] => "/dev/null")
  Process.detach pid
EOBlock
wr.close
if (!Process.wait2(pid).last.success?)
  system 'pause'
end

 要求xclient端也安装了ruby。

感觉Process.spawn()比system()和popen()甚至popen3()之类的好用的多,例如这里结合一个pipe就实现了popen,并且同时保持了子进程的stdout和stderr和父进程相同。

你可能感兴趣的:(server)