2008年4月16日星期三

虚拟机初探之 QEMU

最早了解到虚拟机,是从 Windows 里面的 Virtual PC 开始的,某个时候曾经在天空下载有破解的版本,由于其小巧,并且的确可以让老 dos 等系统起来,又可以跑 Linux,曾让我把玩多时,直到现在我的 MS Windows 里面还保存着那个时候的虚拟机数据。后来听说有了个很牛的 VMWare,可是机器上跑得巨慢。再后来 Virtual PC 被 MS 收购了,就再没有玩过了新的版本了。

进入 Linux 的世界以后,曾经也想过用虚拟机,比如 bochs 是我第一个接触的虚拟机,但是终究没有尝试多用用,随着对把玩各个 Linux distribution 的热情的消退,我开始集中在 fedora 后来迁移到 debian 上了,虚拟机似乎离我越来越远。直到 coLinux 的第二次接触重新点燃了我对虚拟机的热情。因此,准备在这里开始关于虚拟机的系列文章。而第一个也就是我最近才开始使用的 QEMU,偶然的机会让我能从 U 盘上 boot 偶的 Linux :-p

先看看 QEMU 的介绍,
 QEMU is a fast processor emulator: currently the package supports
arm, powerpc, sparc and x86 emulation. By using dynamic translation
it achieves reasonable speed while being easy to port on new host
CPUs. QEMU has two operating modes:
.
* User mode emulation: QEMU can launch Linux processes compiled for
one CPU on another CPU.
* Full system emulation: QEMU emulates a full system, including a
processor and various peripherals. It enables easier testing and
debugging of system code. It can also be used to provide virtual
hosting of several virtual PC on a single server.
.
As QEMU requires no host kernel patches to run, it is very safe and
easy to use.
我们需要先了解虚拟机究竟有些什么划分,才能理解 QEMU 究竟是什么。

对于虚拟技术(virtualization)有多种划分,请参考这篇文章。我们使用的 QEMU 属于 hardware simulation,亦即使用软件模拟硬件,因此效率低下不足为奇。但是注意前面的介绍,QEMU 支持多种体系结构,这使得我们甚至可以利用它测试其他平台,如 ARM 下的程序。这里顺便把其他的几个类型简单的比较一下,如 full virtualization,要求 client OS 是支持底层硬件的,似乎 VMWare (某个版本)属于这一类,虚拟软件本身担负起 mediator,避免 client OS 进入较本身更高的 ring。因此,该方式应该比前者快,速度损失在于 mediation。paravirtualization 这个词我第一次在 Xen 的主页上看到的,它需要通过修改 client OS 的 kernel 避免虚拟机本身 mediation,这样可以进一步提高虚拟机的效率。问题是很多 proprietary OS 是不可能修改其 kernel 的。还有一种是 operating system-level virtualization,这时虚拟机本身作为 OS 存在,而 client OS 作为应用程序。

好了,我们来看看 QEMU 里面都有些什么,
$ dpkg -L qemu
...
/usr/bin/qemu-img
/usr/bin/qemu-i386
/usr/bin/qemu-arm
/usr/bin/qemu-armeb
/usr/bin/qemu-sparc
/usr/bin/qemu-sparc64
/usr/bin/qemu-sparc32plus
/usr/bin/qemu-mips
/usr/bin/qemu-mipsel
/usr/bin/qemu-m68k
/usr/bin/qemu-alpha
/usr/bin/qemu-sh4
/usr/bin/qemu-sh4eb
/usr/bin/qemu-ppc
/usr/bin/qemu-ppc64
/usr/bin/qemu-ppc64abi32
/usr/bin/qemu-x86_64
/usr/bin/qemu-cris
/usr/bin/qemu
/usr/bin/qemu-system-sparc
/usr/bin/qemu-system-x86_64
/usr/bin/qemu-system-mips
/usr/bin/qemu-system-mipsel
/usr/bin/qemu-system-mips64
/usr/bin/qemu-system-mips64el
/usr/bin/qemu-system-arm
/usr/bin/qemu-system-ppc
/usr/bin/qemu-system-ppcemb
/usr/bin/qemu-system-ppc64
/usr/bin/qemu-system-m68k
/usr/bin/qemu-system-sh4
/usr/bin/qemu-system-sh4eb
/usr/bin/qemu-system-cris
/usr/sbin
/usr/sbin/qemu-make-debian-root
...
/etc
/etc/qemu-ifup
...
/usr/share/qemu/openbios-sparc64
/usr/share/qemu/openbios-sparc32
/usr/share/qemu/ppc_rom.bin
/usr/share/qemu/proll.elf
/usr/share/qemu/vgabios-cirrus.bin
/usr/share/qemu/vgabios.bin
/usr/share/qemu/bios.bin
可见,QEMU 对每个支持的体系结构提供了一个命令,另外 /etc 下面的脚本似乎是用来打开虚拟机和主机之间网络的,而/usr/share/qemu 里面是一些 BIOS。另外那个 /usr/sbin 里面的程序是用来制作一个不可以 boot 的 debian 的 / 的 disk file,这个东西应该可以在 coLinux 里面用用。

下面讨论一下一些基本过程:既然 QEMU 是虚拟硬件完成的,那么我们相当于有一个裸机,我们需要给它安装操作系统,配置网络等等。那么它会提供我们哪些外设呢?
-   i440FX host PCI bridge and PIIX3 PCI to ISA bridge
- Cirrus CLGD 5446 PCI VGA card or dummy VGA card with Bochs VESA extensions (hardware level, including all non standard modes).
- PS/2 mouse and keyboard
- 2 PCI IDE interfaces with hard disk and CD-ROM support
- Floppy disk
- PCI/ISA PCI network adapters
- Serial ports
- Creative SoundBlaster 16 sound card
- ENSONIQ AudioPCI ES1370 sound card
- Adlib(OPL2) - Yamaha YM3812 compatible chip
- PCI UHCI USB controller and a virtual USB hub.
因此,我们应该可以利用网络、光驱、硬盘、软盘甚至是 U 盘来启动我们的虚拟机。这在 qemu 的命令行参数里面可以找到,如 -fda 和 -fdb 就是软盘(或者软盘设备,似乎 QEMU 直接用 raw 的,硬盘也是 @@),-hda(bcd) 是硬盘,-cdrom 是光盘。这些设备都是可以用更加复杂的 -drive 产生,里面 if 那个 type 好像是有个 pflash,后面看看是否能用 -,-b。如果不是真需要将更新写入,可用 -snapshot。

然后我们需要确定 boot 的设备,这是可以用 -boot 加上 a(软盘)、c(硬盘)、d(光驱)、n(网络)。内存用 -m n 指定 n Mb 的内存。-smp 可以指定多个 CPU 用于虚拟机。-soundhw 指定声卡类型。-localtime 指定使用当地时间,默认的是 UTC。-k 设定键盘 layout。-usb 和 -usbdevice 将把 USB 设备映射到 VM 上。-net 配置网络,可选 vlan、TAP 等连接方式。后面会详细介绍网络。网络启动需要设置 -tftp 和 -bootp,这和配置 Linux 网络启动的方式一致。-vnc 可以把视频输出到 VNC server,而不是默认的显示在 X11 里面。-smb 设置一个通过 SAMBA 服务共享的文件夹。-redir 设置端口映射,这可以把发送到主机的请求转移到 VM 上。-kernel、-append 和 -initrd 可以设置一个独立的 Linux 内核用于 boot 一个 /。串口通过 -serial 映射,它可以把很多东西当作是 VM 的串口,如 TCP/IP 的连接。

在虚拟机里面可以用 C-M-1、2、3 在 QEMU 的 虚拟界面、moniter 和 serial port 之间切换。在 monitor 里面可以执行需要的命令控制虚拟机的行为(请参看 QEMU 的 user doc),如 commit 和 -snapshot 合用,可以需要的时候把镜像写入磁盘文件;通过 info 查看 network、block、registers 等;quit 退出;change 更改一些参数;screendump 抓屏到 ppm 文件;wavcapture 捕获声音;savevm 和 loadvm 可以保存读取 VM 状态;x、xp 等可以将虚拟机内存中信息 dump 出来;sendkey 像虚拟机发送按键。

说了这么多 manual 里面的东西,下面我们开始配置几台虚拟机玩玩吧。
  • 首先尝试一下传说中的 dos 吧,手头是一个 Windows 98 里面的 MS-DOS 7.0 的 img 文件,比如弄个 50Mb 分配给以后的 DOS,首先通过
    $ qemu-img create -f qcow2 MS-DOS-7.0.qcow2 50Mb
    产生一个会自动增长的 disk file,然后我们通过下面的命令启动
    qemu -fda PWin98.img -hda MS-DOS-7.0.qcow2 -boot a -m 32 -win2k-hack
    可见我们将 Pwin98.img 作为启动盘,分配了 32Mb 内存。可惜这个版本的 DOS 不好用,回头找个好用的 DOS 6.22 还是什么吧,呵呵。
  • 我们再来考虑装一个 debian,使用 ISO 镜像。下载 debian 的 netinst 镜像,用下面的命令启动虚拟机开始安装:
    qemu -m 128 -cdrom debian-40r0-i386-netinst.iso -hda debian.img -net nic -net user
    然后就会像正常安装一样开始安装程序。进行分区什么的,然后配置网络。这里使用的网络是使用用户的网络,如果有 root 权限,可以启用 TAP 等方式,那样甚至可以用虚拟机组成一个网络。
  • 这里我们换用网络安装。boot 一个 debian 需要一些东西:不可少的。同时,还必须让 QEMU 拥有


wikipedia 上面对 QEMU 的评价是对 Windows 等 OS 支持不够完整,有些不常用的体系结构支持也不完整,显卡、声卡等驱动支持差,ms 用很老的版本 gcc 编译的 -,-b,其他的一些相关软件将在后面一一了解,我们知道直接做硬件仿真慢,因此 QEMU 有一些加速模块,主要是把一部分应用程序直接在 CPU 上跑,类似 full virtualization 的效果,如 KQEMU(可通过安装 kqemu-modules 包获得)和 QVM86,另外一些虚拟机如 Virtual Box 基本上是利用了 QEMU 关于 i386 虚拟的这部分,加入了自己的一些东西(比较看好这个 Virtual Box,下一个目标,hoho),还有 Xen-HVM、KVM、Darwine、Win4Lin Pro Desktop。

另外 QEMU 提供了一些类似 wine 的 user-space emulation,即直接在当前操作系统中执行代码(不是在虚拟机里面),如 qemu-i386 等,现在仅仅支持 Linux 和 Darwin。kqemu-modules 仅仅对某些操作系统有效。

有一些 QEMU 的前端,如 QEMU launcher 和 Qemulator。

2008年4月13日星期日

vnc-java 一个 VNC 的 Java applet 客户端

见 vnc-java 包内容,
/usr/bin/jvncviewer
/usr/share/java/vncviewer-3.3.3r2.jar
/usr/share/vnc-java
/usr/share/vnc-java/animatedMemoryImageSource.class
/usr/share/vnc-java/authenticationPanel.class
/usr/share/vnc-java/clipboardFrame.class
/usr/share/vnc-java/DesCipher.class
/usr/share/vnc-java/optionsFrame.class
/usr/share/vnc-java/rfbProto.class
/usr/share/vnc-java/vncCanvas.class
/usr/share/vnc-java/vncviewer.class
/usr/share/vnc-java/hextile.vnc
/usr/share/vnc-java/index.vnc
/usr/share/vnc-java/noshared.vnc
/usr/share/vnc-java/shared.vnc
/usr/share/vnc-java/tight.vnc
/usr/share/vnc-java/zlib.vnc
/usr/share/man/man1/jvncviewer.1.gz
/usr/share/java/vncviewer.jar
/usr/share/vnc-java/vncviewer.jar
其实主要就是 /usr/share/vnc-java 这个目录了,里面的 class 文件就是 applet 需要的东西,vnc 文件是一套模板。怎么用这个东西呢?

比如我们把上面文件放在 ~/vnc-html 里面,则可以如下调用 vncserver,
$ vncserver :1 -geometry 640x480 -depth 16 -httpd ~/vnc-html -httpPort 5678
这样,将在本地 5678 端口建立一个 mini http 的服务器(Xvnc 这个进程负责),并用 vnc 文件作为模板生成页面(上面含有 java applet)。这样在浏览器上输入 http://ur-ip-or-url:5678 即可打开该页面,如果你的浏览器支持 java applet(现在使用的 jre 1.5 可以正常浏览,但是 1.6 不行),就应该看到登录界面了。

那么这是什么原理呢?是否可以用一个一般性的 http 服务器实现这个过程呢?那么我们来看看上面那些 vnc 文件都有些什么吧!
<!-- index.vnc - default html page for Java VNC viewer applet.  On any file
ending in .vnc, the HTTP server embedded in Xvnc will substitute the
following variables when preceded by a dollar: USER, DESKTOP, DISPLAY,
APPLETWIDTH, APPLETHEIGHT, WIDTH, HEIGHT, PORT. Use two dollar signs
($$) to get a dollar sign in the generated html. -->

<HTML>
<TITLE>
$USER's $DESKTOP desktop ($DISPLAY)
</TITLE>
<APPLET CODE=vncviewer.class ARCHIVE=vncviewer.jar
WIDTH=$APPLETWIDTH HEIGHT=$APPLETHEIGHT>
<param name=PORT value=$PORT>
</APPLET>
<A href="http://www.tightvnc.com/">www.TightVNC.com</A>
</HTML>
注意,其中一些 $ 开始的是关于 VNC server 的一些参数,由 Xvnc 运行时替换。这样我们不难知道,实现一般 http server 的方式就是将这些对应的页面放在 http server 的合适目录下面,然后将这些 vnc 文件通过某种方式变成 html(估计写个 sed 或者直接 shell 就可以替换掉这些东西了)。

但是这个 applet 必须直接能访问到 vnc server,如果中间被防火墙隔开了,也就没有用了。

2008年4月7日星期一

GNU screen

我们先从 terminal 讲起,传统意义的 terminal 一般只有一个监视器和键盘,通过如串口等直接与主机相连,为了实现这一模型需要硬件和软件的协同工作。硬件上,该 terminal 必须自带一个字库,含有一定的 buffer,当主机上的数据传送过来通过查字库获得显示的信息,进而在监视器上显示出来。另一方面,敲击键盘时,实际上直接将按键信息发送到主机,主机通过回显(echo)的方式把对应的数据返回到 terminal,或者不返回。

这个模型势必存在下面的问题,主机可能并不知道 terminal 能够以多快的速率接受数据,也不知道通过什么样的方式使得 terminal 实现自己需要的效果。这都是由硬件决定的,没有办法更改的。现在,似乎纯粹的 terminal 已经不多见了,取而代之的是基于个人电脑的 terminal,也就是所谓虚拟终端。尽管虚拟终端的能力上已经比原来强大了很多,但是原先遗留下来的一些硬件标准必须依靠合适的软件来模拟。同时,如 Microsoft 已经不满足于基于文字的终端的要求,它所基于别人的协议开发的 RDP(也是 Windows Terminal Service)就是一个允许通过 GUI 实现的虚拟终端。

更多关于 terminal 的知识,可以参考 Text Terminal HOWTO 文献。

那么 GNU screen 是什么呢?这是 screen 的 info 中给出的介绍:
Screen is a full-screen window manager that multiplexes a physical terminal between
several processes, typically interactive shells. Each virtual terminal provides the
functions of the DEC VT100 terminal and, in addition, several control functions from
the ISO 6429 (ECMA 48, ANSI X3.64) and ISO 2022 standards (e.g. insert/delete line
and support for multiple character sets). There is a scrollback history buffer for
each virtual terminal and a copy-and-paste mechanism that allows the user to move
text regions between windows.
可见 screen 的作用就是把一个物理终端(包括虚拟终端)分成多个窗口(虚拟终端)。那么它有什么用呢?第一,某些终端上不允许产生多个窗口,因此如果在某个程序运行中希望获得另外一个程序给出的信息,往往只能通过向本程序发出 suspend 信号(^Z),这时可利用 screen 的多窗口特性解决;第二,往往运行了某一个程序后希望它在后台执行,但是等到希望 logout 时,发现该程序没有执行完,尽管可以用 nohup 解决,但是一般可能忘记预料到这点,screen 允许这个时候用户与其 detach,并 logout,这也避免了使用不稳定线路(如 modem、wifi)接入的用户的不必要损失;第三,screen 允许多个用户共用一个虚拟终端,这使得 TUI 协作变得可能(VNC 使得 GUI 协作变得可能)。这里给出一个参考网站

我们先从基本的 screen 使用说起。screen 有一个配置文件,一般在 /etc/screenrc,可以把它复制到 ~/.screenrc,然后编辑它,里面都是 screen 支持的命令,这些命令可以在进入 screen 后用 C-a : 来输入,实时的产生效果。其实 screen 默认的 key binding 下,所有的命令都是用 C-a 开头的。如果没用过 screen,可以直接输入,就会进入到 screen 里面,你会发现只是又进入到了一个新的 shell 里面,该 shell 继承了运行 screen 的 shell 的环境变量。如果你想暂时离开 screen,甚至是退出本次登录(结束运行 screen 的这个 session),那么可以直接 C-a d,这会和 screen detach,但是并没有结束该 screen 的 session。等你什么时候记得 screen 的时候,也许换了一种连接主机的方法(可以从网络、直接用 console、从 serial port 还是别的什么)连接到该主机,可以用 screen -list 看到一共你打开过了多少个 screen sessions。然后可以选择连接哪一个,比如某一个处于 detached 状态,那么你可以 screen -r name(如果仅有一个可以省略)。如果处于 attached 状态,你想 detach 原来的连接,则可以 screen -d -r,但是你也许还希望不断开直接连接上,那么 screen -x -r,很有意思的是这样连上去两边可以同时看到某个窗口的变化,但是又允许使用不同的窗口分别同时完成任务。那么怎么建立新的窗口呢?一般说来可以在已有的 screen 里面继续激活 screen(不带有 -m 参数),或者通过 screen command 在新窗口执行该命令(执行完后会关闭该窗口),不过最简洁的还是 C-a c 了。为了在已有的窗口之间跳转,可以使用 C-a " 获得所有窗口的列表并进行选择,或者直接 C-a 0-9 切换,还可以 C-a n/p 在前后两个窗口切换,而 C-a a 则和 Emacs 的 C-x b 一样,很方便在两个窗口间跳转。如果不需要某个窗口可以在 shell 里面 exit,当然 C-a k 比较方便,而临时不用可以用 C-a x 锁定。最好的在线帮助就是 C-a ?,这会给出一些最常用的 key binding。

下面我们将就一些较高级的应用做出说明。
  • 可能你需要回滚屏幕以查看那些超出屏幕上缘的信息,可是你发现 Shift + Page Up/Down 不再有用了,难道是 screen 不支持吗?再看看顶上 info 里面的介绍吧,怎么可能!的确是支持的,C-a [,你发现这时居然可以任意的移动光标了,如果你记得看一下 C-a ? 的说明的话你会发现其实你进入的是 copy mode,换句话说在这种情况下你可以将一个 window 里面的信息复制出来,然后通过 C-a ] 贴到另外一个 window 里面去,你在自己的 terminal 里面没有诸如 gpm 或者 gnome-terminal 的复制粘贴功能而你又需要的时候,你就会感谢 screen 的作者这都帮你想到了。
  • -r 和 -R,-d 和 -D,大写的一般都比较牛一点,如 -R 在没有可以 reattach 的情况下允许创建一个新的 screen session,-D 甚至可以 detach 并让远程退出。这样可以依照你的需求组合出你需要的效果。-RR 表示如果存在多个 session 则处理第一个。
  • -S,如果不喜欢默认的 session 名字可以用 -S 加入。
  • 前面说道 multi-display 的 -x,实际上 screen 另外支持 multi-user,但是似乎这个代价有点得不偿失,这个连接里面提到需要给 screen 设置 set-uid 位,还需要改变 /var/run/screen 的 user mode 为 755。然后才能按照这里的说法配置成功,而 debian 默认是不许可的。
  • 可以和 Emacs 一样将一个窗口分成两个,命令是 C-a S,切分后可以用 C-a TAB 将焦点换到另外的部分,C-a Q 关闭除当前以外所有,C-a X 关闭当前。
  • 可以给 window 设置 title,命令是 C-a A。可以用 C-a w 获得列表,或者 C-a ' 选择跳转。这个可以设置为一个动态的。
  • 如果 screen 显示不正常,可以用 C-a l 重绘。另外如果出现花屏,可以用 reset 命令,或者 C-a Z。
  • 在 copy mode 里面用 SPC 设置复制区域,Y 可以复制一行,W 是一个单词。/ 进行搜索。
  • 如果需要自己的 key binding 可以用 bind 命令绑定,格式是 bind key command,这里 key 里面 ^x 表示 C-x。

几个程序的简介

前面列出来了一摞程序,这里收集了一些较为详细的介绍,暂不深入了:
  • grcm: GNOME application to initiate connections to remote machines GNOME Remote Connection Manager is an application that provides an easy way to initiate connections to remote machines. Its primary goal is to provide a GUI to launch ssh, telnet and rdesktop type of applications, however it is highly configurable. 可以通过它方便的建立 ssh、telnet 和 rdesktop 连接,怎么感觉跟 putty 的功能很像。
  • tsclient: 提供一个 gnome 的 panel 方便选择,可以直接读取 MS 的 rdp 文件,同时支持 vnc、ICA 和 X via nest。
  • krdc: krdc is an KDE graphical client for the rfb protocol, used by VNC, and if rdesktop is installed, krdc can connect to Windows Terminal Servers using RDP.
  • autocutsel: This tracks changes in the server's cutbuffer and clipboard selection. when the clipboard is changed, it updates the cutbuffer. When the cutbuffer is changed, it owns the clipboard selection. The cutbuffer and clipboard selection are always synchronized. In the case of a VNC client since it synchronizes the Windows' clipboard and the server's cutbuffer, all three "clipboards" are always kept synchronized. When you copy some text in Windows, the cutbuffer and the clipboard selection are updated. When you copy text on the server using either the cutbuffer or the clipboard selection, the Windows's clipboard is always updated.
  • conspy: Conspy allows a (possibly remote) user to see what is displayed on a Linux virtual console, and send keystrokes to it. It is rather like VNC, but where VNC takes control of a GUI conspy takes control of a text mode virtual console. Unlike VNC, conspy does not require a server to be installed prior to being used.
  • directvnc: DirectVNC is a client implementing the remote framebuffer protocol (rfb) which is used by VNC servers. If a VNC server is running on a machine you can connect to it using this client and have the contents of its display shown on your screen. Keyboard and mouse events are sent to the server, so you can basically control a VNC server remotely. 不过这是用 framebuffer 的 VNC client。
  • gnome-rdp: gnome-rdp is a Remote Desktop client for GNOME. It supports RDP, VNC and SSH protocols. It is also possible to configure and save sessions to have a faster access.
  • linuxvnc: linuxvnc can export your currently running text sessions to any VNC client. It can be useful if you want to move to another computer without having to log out or to help a distant colleague solve a problem.
  • pyvnc2swf: Pyvnc2swf captures screen motion using the VNC protocol and generates a Shockwave Flash (SWF) movie which can be played back in any browser supporting the SWF format. 可以用来录制操作,hmm 不错。
  • screenkast: Screenkast let you record your activities performed on a vncserver.It connects to the server and act like a windows manager, but when you close the viewer, it imports the recording and let you modify them by adding some fancy docs during the video. The resultant file is a .isd, but can be exported to many formats directly from screenkast. 类似,只是不知道 isd 能转化成什么。
  • tightvnc 系列,似乎新的 vnc4 已经提供了类似的能力。
  • vncsnapshot: VNC Snapshot is a command-line program for VNC. It will save a JPEG image of the VNC server's screen.
  • vinagre 又是一个 GNOME 的客户端,With Vinagre you can have several connections open simultaneously, bookmark your servers thanks to the Favorites support, store the passwords in the GNOME keyring, and browse the network to look for VNC servers.
  • x11vnc: x11vnc allows one to view remotely and interact with real X displays (i.e. a display corresponding to a physical monitor, keyboard, and mouse) with any VNC viewer. It has built-in SSL encryption and authentication, UNIX account and password support, server-side scaling, single port HTTPS and VNC, mDNS service advertising, and TightVNC and UltraVNC file-transfer.
  • x2vnc: This program merges the capabilities of x2x and vncviewer. It will allow a machine with an X display and a machine with a VNC server running on its main screen to act as if they were two displays connected to one machine. When you move your mouse pointer off the screen in a direction of your choosing, the pointer will appear on the other screen instead. 似乎 x2x 更好玩...
  • xwnc: It draws nothing on your screen, every things is drawn into pixmaps. Similarly as Xvnc, but with a different protocol, Xwnc can send these pixmaps (and others information) to a "viewer". FvwmAmetista is such a viewer, it uses OpenGL (via nucleo) for rendering the X desktop into a window of a "regular" 3D accelerated X server.

vino 远程控制已有的 X

前面的输出中说道 vino 是 gnome 的 VNC server,这其实是说它是 GNOME 的子项目,事实上你不在 GNOME 里面一样可以用 vino。我们观察一下下面的命令,这里仅仅列出了感兴趣的东西:
...
/usr/lib/bonobo/servers
/usr/lib/bonobo/servers/GNOME_RemoteDesktop.server
/usr/lib/vino
/usr/lib/vino/vino-server
/usr/bin
/usr/bin/vino-preferences
...
/usr/share/doc/vino/changelog.Debian.gz
/usr/share/doc/vino/README
/usr/share/doc/vino/copyright
/usr/share/doc/vino/AUTHORS
/usr/share/doc/vino/NEWS.gz
/usr/share/doc/vino/changelog.gz
...
/usr/share/applications/vino-preferences.desktop
...
/usr/share/vino/vino-prompt.glade
/usr/share/vino/vino-preferences.glade
/usr/share/gconf
/usr/share/gconf/schemas
/usr/share/gconf/schemas/vino-server.schemas
我们依次来研究这些文件是什么。如果你需要急着用 vino,那么直接运行 vino-preferences 设定密码等参数,然后 /usr/lib/vino/vino-server 打开它就好了。默认情况下它使用和 VNC 一样的端口。

我们看见了一个叫 bonobo 的东西,在 libbonobo2-common 里面解释道它是 a set of language and system independent COBRA interfaces for creating reusable components, controls and creating compound documents,该库是 gtk+ 上的一个实现,因此这是 vino 成为 GNOME 一个组件的方式。后面将研究这种关系的细节。通过对 vino-server 使用 ldd 就能看见它的确与 libbonobo 进行了连接。

在 vino-preferences.desktop 里面可以看见很多 name 和 comment,这是根据不同的 locale 设定的。而 /usr/share/applications 就是用来存放这些“快捷方式”的。

两个 glade 文件表明 vino 本身很可能利用了 glade 来动态的产生界面,这是 gkt+ 的一个很有意思的地方,和 Qt 使用 Qt-designer 设计界面类似,glade 是 gkt+ 的界面设计程序,存下来的 glade 文件被 libglade 解析,动态的产生界面。

最后是 gconf,根据 libgconf-dev 的解释,gconf 用于用于存储应用程序配置的一个数据库,这样我们就知道 vino 所存储的密码信息其实应该是通过 gconf 放在了某处。GNOME 的程序可以通过它获得较为一致的存储风格,具体我们会在后面分析。

好,既然有了 x0vncserver,那么为什么还要有 vino 呢?我们可以尝试一下两者是否可以替换。首先通过 vncpasswd 设置密码,然后打开 x0vncserver,

$ x0vncserver PasswordFile=~/.vnc/passwd
这时可以用 vncviewer 连接到该服务器,同样,对于 vino 而言设置好后也可以。又比如打开后通过 xrdp 的 libvnc.so 都可以正常工作。因此两者实现了相同的功能。但是 x0vncviewer 不允许使用长度超过 8 的密码,不知道 vino 是否取消了该规定。如果怕 VNC 协议上没考虑这个问题,那么可以用 x0vncviewer 关闭非 localhost 的连接,而仅仅使用 xrdp 的认证,由于 xrdp 使用了加密的隧道,因此要安全一些。vino 似乎没有多少帮助文件,仅仅只能通过 vino-preferences 来设置。在 2.22 以前的版本 vino 没提供完整的设置功能。现在用起来倒是差不多了,如果你不讨厌 vino-server 连接上的 N 个 so,习惯了 GNOME 环境,那么用 vino 也未尝不可。个人倾向于 x0vncserver,因为它提供的功能更加正交一些,呵呵。

2008年4月6日星期日

使用 VNC 进行远程控制

先看一段命令的输出吧,
$ apt-cache search vnc
autocutsel - Keep the X clipboard and the cutbuffer in sync
conspy - Remote control of Linux virtual consoles
directvnc - VNC client using the framebuffer as display
gnome-rdp - remote desktop client for GNOME
iprelay - User-space bandwidth shaping TCP proxy daemon
kcemirror - Windows CE remote control tool like VNC
libgtk-vnc-1.0-0 - A VNC viewer widget for GTK+ (runtime libraries)
libgtk-vnc-1.0-dev - A VNC viewer widget for GTK+ (development files)
libsvncpp-dev - Subversion C++ library (development files)
libsvncpp0c2a - Subversion C++ shared library
libsvnqt4 - Qt wrapper library for subversion
libvncserver-dev - API to write one's own vnc server - development files
libvncserver0 - API to write one's own vnc server
libvncserver0-dbg - debugging symbols for libvncserver
linuxvnc - VNC server to allow remote access to a tty
python-gtk-vnc - A VNC viewer widget for GTK+ (python binding)
pyvnc2swf - screen recording tool to SWF movie
qemulator - a solution for easy setup and management of qemu
screenkast - Record your activities on the screen
tightvncserver - virtual network computing server software
tkvnc - Displays a list of (defined) machines to start VNC to
tsclient - front-end for viewing of remote desktops in GNOME
vinagre - VNC client for the GNOME Desktop
vino - VNC server for GNOME
virt-manager - desktop application for managing virtual machines
virt-viewer - Displaying the graphical console of a virtual machine
vnc4server - Virtual network computing server software
vncsnapshot - A utility that takes JPEG snapshots from VNC servers
vtgrab - A VNC like console monitoring
x11vnc - VNC server to allow remote access to an existing X session
x2vnc - A dual-screen hack - link an MS-Windows and X display
xrdp - Remote Desktop Protocol (RDP) server
xtightvncviewer - virtual network computing client software for X
xvnc4viewer - Virtual network computing client software for X
xwnc - Mix of Xvnc and XDarwin with improved protocol
tightvnc-java - TightVNC java applet and command line program
vnc-java - VNC java applet and command line program
krdc - Remote Desktop Connection for KDE4
krfb - Desktop Sharing for KDE4
vnc4-common - Virtual network computing server software
xvncviewer - Virtual network computing client software for X
也不知道为什么 VNC 也可以把 RDP 搜索出来。这里我们主要关心 xvncviewer、vnc4-common 和 vnc4server。

我们都知道用 vncviewer 在命令行上激活 VNC 的客户端,其实 debian 里面耍了个小滑头,/usr/bin/vncviewer 其实是一个符号链接,指向了 /etc/alternatives/vncviewer,这个目录里面的几乎全部是符号链接,里面都是一些可能存在多个可能的程序,如 window manager、yacc 等,这里相当于给出了选择,顺藤摸瓜可知 /etc/alternatives/vncviewer 其实是 xvncviewer 里面的 /usr/bin/xrealvncviewer。这样你就明白如果上面列表里面你装了多个 VNC clients 怎么选择一个默认的作为你常用的 vncviewer 命令了吧。

VNC clients 只能与 VNC 的 server 连接,在 Linux 里面每一个 server 其实就是一个 X 服务器(后面详细解释)。因此 vncviewer 很多命令和 X 启动的参数很像,同时命令对象就是 host:#display 的形式。这一点比较麻烦,因为如果每个用户都打开了自己的 VNC server,那么必须得记住自己的 #display,否则就不知道怎么连接了。这里介绍几个比较有意思的参数:-via host,建立一个从本地到 host 的 ssh 通道,由该通道将 VNC 连接 forward 到 host 一端。关于 ssh tunnel 的东西我们将在后面介绍。-listen 用作反向连接,-shared 使得同时连接在同一个 server 上的 client 不会掉线,-fullscreen 进入全屏模式(F8 打开 client 的菜单)。

这里我们提到了所谓的反向连接,那么让我们看看 server 有些什么。类似的 /usr/bin/vncserver -> /etc/alternatives/vncserver -> /usr/bin/vnc4server。vnc4server 包里面还有 vnc4config、Xvnc4、x0vncserver 等工具。vnc4server 的作用类似于 startx 脚本,就是用来激活 Xvnc4 这个 X server 的,注意X server 有好几种,如 X(xorg 的)、Xvnc4、以及前面提到的 x11rdp,它们的作用就是接受 X client 的显示输入,并以合适的方式显示(显示在本地屏幕上、通过 VNC 连接显示在客户端、通过 RDP 传输到客户端)。VNC server 需要配置一个类似于 .xinitrc 的文件,一般放在 ~/.vnc/xstartup 里面,我们可以让它指向 ~/.xinitrc 文件,这样 Xvnc4 就和我们本地的 X 起来的时候干相同的事情(启用相同的 Window Manager 和其他的应用程序)。另外还要一个登录密码,这会保存在 ~/.vnc/passwd 里面。比较常用的参数也就是设置 -name、-geometry 和 -depth 了。另外可以通过 -kill 结束某一个 VNC server。

Xvnc 作为 X server 自然是最复杂的东西了,除了前面 xvnc4server 传递的信息以外,另外有 -httpd dir 表示将 dir 目录作为一个 mini http 服务器的根,这是为了方便利用 java applet 访问该 VNC 服务器,该服务器的端口可用 -httpPort 指定。如果需要这些 applet,前面的列表中有 vnc-java 或 xtightvnc-java 供使用,也可以看出来 xtightvncviewer 是 vnc4viewer 的另一种选择。为了使得两边的剪切板能共用,可以用 -SendCutText 和 -AcceptCutText。-QueryConnect 会对本地进行询问确认是否建立连接。Xvnc4 的行为可以用 vnc4config 来控制,如 -disconnect 将会去掉所有的 clients,而通过 -list、-set、-get 和 -desc 将能更加细致的控制其行为。如,
$ vncconfig -display :1 -list
localhost
desktop
rfbport
rfbwait
httpPort
httpd
rfbauth
QueryConnectTimeout
AlwaysSetDeferUpdateTimer
DeferUpdate
Log
QueryConnect
SendCutText
AcceptCutText
AcceptPointerEvents
AcceptKeyEvents
DisconnectClients
NeverShared
AlwaysShared
Protocol3.3
CompareFB
ClientWaitTimeMillis
IdleTimeout
Password
PasswordFile
ReverseSecurityTypes
SecurityTypes
BlacklistTimeout
BlacklistThreshold
RemapKeys
ZlibLevel
MaxCutText
可见几乎所有的 Xvnc4 的 man page 里面的属性都可以通过该命令进行配置。其中 -connect 可以使得 server 主动连接向 -listen 的 client。一种可能的应用在于从一个服务器端向瘦客户端批量进行连接,这样使得每个 client 桌面上都显示出完全一样的结果,hmm 似乎可以用在教学上...

我们来看看神秘的 x0vncserver 是什么吧。它的 man page 中写道 x0vncserver is a VNC server which continuously polls any X display, allowing it to be controlled via VNC,换句话说其实就是和 vino 类似咯。我们将在后面讨论 vino。

为了创建 VNC 的密码,应该用 vnc4-common 的 vnc4passwd。

2008年4月5日星期六

xrdp 远程桌面协议服务器

其实 Linux 实现的仅仅是 RDP 本身,而像 Windows 使用的远程桌面一个重要特点就是可以尽量避免传输 bitmap 信息,由于传输的是高级画图信息,这使得传输的数据量有明显减少,从而在一定的网络负荷下仍然可用。而 xrdp 一般仅仅是做一个 bitmap cache,并通过压缩减少网络流量,除非使用 libxup.so 模块(由于使用 X11rdp,传输的信息也是高层绘图信息)。

xrdp 说穿了是一个 proxy,它通过几个 lib*.so 与底层交互,如可以用服务器端的 VNC server,或者将 RDP 请求传送到一台 Windows 上进行共享。我们来看一看一个典型的 xrdp 服务是如何提供给用户的:一个 rdp client 连接到 xrdp,首先通过交换公钥建立可靠的数据通道,client 要求对应的屏幕大小和色彩深度,server 返回一个简易的模块选择界面,并要求 client 登录认证。client 完成了登录信息以后,server 首先依靠 sesman 进行认证,然后依照其选择的模块激活对应的功能,如 libvnc.so,建立连接。

client 可以选择的模块是由 server 在 /etc/xrdp/xrdp.ini 里面定义的。该文件有一个 global 的 section,主要是定义一些控制服务器的参数,如是否打开 bitmap cache,是否是用压缩等。后面一般是根据连接类型产生的 section,例如
[xrdp1]
name=sesman-Xvnc
lib=libvnc.so
username=ask
password=ask
ip=127.0.0.1
port=-1
是一段 debian 中默认的配置,[] 里面是第一个 xrdp 模块,对应的 name 是显示给 client 看见的,调用的是 libvnc.so 和 VNC 服务器交互,username 使用 ask 表明向用户询问,也可以固定下来,ip 和 port 就是连接的 VNC 服务器地址。port=-1 表明使用默认的可用地址。又比如
[xrdp5]
name=rdp-any
lib=librdp.so
ip=ask
port=ask3389
是使用上级 RDP server,比如可以通过该连接访问处于 xrdp 后的 Windows 主机。另外还有一种
[xrdp6]
name=sesman-X11rdp
lib=libxup.so
username=ask
password=ask
ip=127.0.0.1
port=-1
是利用 X11rdp,理论上应该是最快捷的了,可惜现在的 debian 并没有实现 X11rdp 的模块,有人已经在呼唤了。

关于 sesman,作用很简单认证,启动合适的 X,如 Xvnc 或者是 X11rdp,或者是连接到远程 Windows 上。控制其行为的是 /etc/xrdp/sesman.ini 文件,分为四个 section,global、logging、security、sessions。global 中重要的是设置了用户 WM,
[Globals]
ListenAddress=127.0.0.1
ListenPort=3350
EnableUserWindowManager=1
UserWindowManager=/etc/xrdp/startwm.sh
DefaultWindowManager=/etc/xrdp/startwm.sh
这使得我们可以依据自己的喜好定义自己的脚本。其实 startwm.sh 本身就是指向 /etc/X11/Xsession 的。

RDP Clients 远程桌面协议客户端

在 Linux 里面有时需要远程控制 Windows 里面的东西。我们都知道在 Windows 里面通过 [Windows]\System32\mstcs.exe 可以建立远程桌面控制连接。这种连接使用的协议在 Linux 里面一般叫 RDP(Remote Desktop Protocol),这里我们就讨论一下相关的客户端。

这是一段命令输出:
$ apt-cache search rdesktop
grcm - GNOME application to initiate connections to remote machines
grdesktop - GNOME frontend for the rdesktop client
osso-af-settings - pkg-config based registry for maemo directories
rdesktop - RDP client for Windows NT/2000 Terminal Server
remotedesk.app - Remote Windows access tool for GNUstep
tsclient - front-end for viewing of remote desktops in GNOME
xrdp - Remote Desktop Protocol (RDP) server
krdc - Remote Desktop Connection for KDE4
这里我们仅仅讨论 rdesktop 和 grdesktop。

前者作为命令行上的 RDP 客户端简洁易用,一般学会
rdesktop -u 用户名 主机地址
就行了,高级的参看 man page。比较有用的选项一个是 -f 选择全屏(C-M-ENT 退出该模式),再就是 -g 选择窗口大小,-A 激活 seamless RDP,-r 将设备做出映射,使得客户端的设备出现在服务器端,比如串口、打印口(并口)、磁盘、声音(服务器到客户端)。

grdesktop 简化了你对这些东西记忆的需要,并且可以保存连接供将来使用。