泰晓科技 -- 聚焦 Linux - 追本溯源,见微知著!
网站地址:https://tinylab.org

基于泰晓RISC-V实验箱的Linux公开课
请稍侯

noVNC 简介

Wang Chen 创作于 2019/10/14

By unicornx of TinyLab.org Sep 24, 2019

什么是 noVNC ?

noVNC 是一个 HTML5 的 VNC 客户端,采用 JavaScript 编程实现。其主要功能是和远端的 VNC Server 互通,通过对 RFB(Remote Frame Buffer)协议 数据的编解码,一方面接收远端 VNC Server 发送的数据,解码后通过 Cancas 技术绘制在客户端侧,另一方面将客户端侧的终端输入编码成 RFB 数据发送给远端的 VNC Server。也就是说有了 noVNC,我们可以直接使用支持 HTML5 的 Web 浏览器,譬如 Chrome,就可以访问远端的安装了 VNC Server 的机器的桌面,而不用另外安装原生的 VNC 客户端(譬如我们经常在 Windows 上安装的 RealVNC Viewer)。

但需要注意的是,具体传输时,和原生的 VNC 客户端不同,原生的客户端的 RFB 数据是直接承载在 TCP (Raw TCP)上,而 noVNC 处理的 RFB 数据是承载在 Websocket 之上。由于目前大多数 VNC 服务器都不支持 WebSockets,所以 noVNC 是不能直接连接 VNC 服务器的,怎么办呢?这就需要一个代理来实现 Websockets 和 Raw TCP 之间的转换,这个代理就是 Websockify。

图 1:Websocket 网络协议栈

Websockify 主要是采用 Python 开发,其主要功能就是实现 Websockts 和普通 TCP 数据包之间的转换。Websockify 原先被叫做 wsproxy,是 noVNC 项目的一部分,但现在被独立出来,作为一个独立的代理服务开发。这么做也是合理的,因为根据我们前面的描述,引入 websockify 代理的原因是因为有些 vnc 服务端不支持 websockets 传输,而对于那些可以支持 websockets 传输的 vnc 服务器,我们完全可以省掉 websockify。

一个典型的从客户端浏览器到 VNC 服务器,中间经过 Websockify 转换的网络如下,注意其中 noVNC 作为一个 HTML5 的客户端,虽然一开始是存放在 websockify 所在的代理服务器上,但其主体 js 代码会在客户端浏览器访问 websockify 服务时被下载到客户端的浏览器中执行。

图 2:noVNC + Websockify 网络拓扑图

搭建 noVNC + websockify 代理服务器

本文介绍的安装方法是直接基于 noVNC 项目的源码进行安装,当然如果你使用的是像 Ubuntu 那样的自带包管理器的发行版本,也可以使用 apt 自行安装,但不保证是最新的版本。

如上图所示,为描述方便,假设在物理上,上图中的所有机器在同一个网段 192.168.1.x 内。

前提:已经在 VNC 服务器上(其 ip 地址为 192.168.1.140)运行了一个 vncserver 的实例,譬如运行了 vncserver :1。由于 vncserver 还未支持 websockets,所以我们还是需要 websockify 代理的,上图依然有效。

假设我们准备将 192.168.1.130 作为 websockify 的代理服务器,我们可以将 noVNC 安装在这台机器上,当然 noVNC 的代码和 websockify 的代码可以不在一台物理机器上,这取决于实际的部署,在本例中放在一起部署。

先在 websockify 代理服务器 192.168.1.130 上安装必要的依赖:

$ sudo apt-get install git
$ sudo apt-get install python-numpy

安装 git 是因为我们需要从官方 github 仓库下载 noVNC 和 websockify 源码;安装 python-numpy 是因为 Websockify 运行时依赖这个 python 库,如果不装这个,运行 WebSockify 时会提示:WARNING: no 'numpy' module, HyBi protocol is slower or disabled。至于 python,这里没有额外安装,缺省我认为你的 Linux 环境下应该是已经有了。

用 git 克隆 noVNC 的最新官方源码,本文实验环境中的版本应该是比 v1.1.0 还新的一个版本 (commit id 为 9886d5),直接取的 master。下载后进入 noVNC 目录。

$ git clone https://github.com/novnc/noVNC.git
$ cd noVNC

我们可以先简单地运行一个 noVNC 提供的缺省启动脚本,快速尝鲜一下 noVNC 的运行效果。

$ ./utils/launch.sh --vnc 192.168.1.140:5901
Warning: could not find self.pem
No installed websockify, attempting to clone websockify...
Cloning into '/home/u/ws/noVNC/utils/websockify'...
remote: Enumerating objects: 12, done.
remote: Counting objects: 100% (12/12), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 4150 (delta 3), reused 5 (delta 1), pack-reused 4138
Receiving objects: 100% (4150/4150), 4.57 MiB | 1.80 MiB/s, done.
Resolving deltas: 100% (2734/2734), done.
Checking connectivity... done.
Using local websockify at /home/u/ws/noVNC/utils/websockify/run
Starting webserver and WebSockets proxy on port 6080
WebSocket server settings:
  - Listen on :6080
  - Web server. Web root: /home/u/ws/noVNC
  - No SSL/TLS support (no cert file)
  - proxying from :6080 to 192.168.1.140:5901


Navigate to this URL:

    http://u:6080/vnc.html?host=u&port=6080

Press Ctrl-C to exit

从上面的运行输出 log 可以看到,当第一次运行时,如果本地还未安装 websockify,noVNC 会自动从 github 的 websockify 仓库 clone 一份,并存放在 utils 目录下新建的一个 websockify 的目录中。

克隆完成后就会帮我们自动运行 websockify 代理服务,注意在没有特殊指定的缺省情况下 websockify 服务的端口为 6080。

这样 websockify 代理服务就启动完毕,可以在客户机(192.168.1.110)的浏览器中输入 http://192.168.1.130:6080/vnc.html 访问远程 VNC 服务。注意这里的 vnc.html 就在我们克隆下来的 noVNC 代码目录下。

图 3:noVNC 登录远程桌面,界面一

点击 “链接” 后输入 VNC server 上设置的密码

图 4:noVNC 登录远程桌面,界面二

这时远程服务器上的桌面就出现了,是不是很酷。

图 5:noVNC 登录远程桌面,界面三

更高级的操作

倘若我们存在多台远程桌面想通过 noVNC 访问,难道要给每一台机器都安装自己的 websockify 代理,然后分别去访问它吗?显然这种做法是繁琐笨拙的。实际上,我们只需要一台机器作为 websockify 代理,其他被访问的机器安装 VNC server 就可以了。如下图:

图 6:一个更复杂的 noVNC + Websockify 网络拓扑图

为了方便地访问多个远程 VNC 桌面,为此我们可以利用 websockify 提供的功能,在代理机器上创建一个 token 配置文件,本质上就是给每台 VNC 桌面起一个别名,以后可以通过 token 文件中配置的 “别名” 访问远程桌面,不需要记住每台 VNC 服务器的具体 IP 地址和端口号信息。

以上图为例,假设我们有三台 VNC 服务器,IP 地址分别是 192.168.1.140192.168.1.141192.168.1.142,vnc 服务都各自启动了 vncserver :1。我们给他们分别起 token (别名)为:test1test2test3。则我们可以创建一个 token 的配置文件内容如下:

$ pwd
/home/token/
$ cat ./token.conf 
test1: 192.168.1.140:5901
test2: 192.168.1.141:5901
test3: 192.168.1.142:5901

假设为该文件的存放路径是 /home/token/token.conf。文件创建好后,我们就可以在 noVNC 的代码仓库目录(这里是 /home/u/ws/noVNC/)下手动启动 websockify 代理服务如下:

$ ./utils/websockify/websockify.py \
--web /home/u/ws/noVNC/ \
--token-plugin TokenFile --token-source /home/token/token.conf \
8787 
WebSocket server settings:
  - Listen on :8787
  - Web server. Web root: /home/u/ws/noVNC
  - No SSL/TLS support (no cert file)
  - proxying from :8787 to targets generated by TokenFile

这里的几个命令选项解释如下:

  • --web /home/u/ws/noVNC/: --web 选项指定代理服务到哪里去找 noVNC 的网站文件,上例给出的搜索路径是 /home/u/ws/noVNC/, 就是我们克隆下来的 noVNC 的代码主目录,在这里有我们在浏览器里需要访问的 vnc.html

  • --token-plugin TokenFile --token-source /home/token/token.conf:这里是比较新的版本中支持的语法,对应的旧的语法是 --target-config=/home/token/token.conf。其目的是告诉代理服务器到哪里去找到 token 文件。

  • 8787:可以修改代理的服务端口,缺省是 6080,这里修改为 8787

还有一些其他常用的选项,譬如:

  • -D: 以后台守护进程(Daemon)方式启动,这样就不会在屏幕上输出日志了。

  • 具体选项说明可以参考 websockify 目录下的 README.md 文件,但这个文档更新的不是很及时,更多更详细的命令选项可以参考 websockify 的源码 websockify/websockify/websocketproxy.py 中的 websockify_init 函数。

如果我们要访问 192.168.1.140 那台vnc 服务器,则我们可以在浏览器中输入:http://192.168.1.130:8787/vnc.html?path=websockify/?token=test1 就可以看到如下的界面,后面的操作和前面的就一样了。同理如果我们要访问 192.168.1.141 那台vnc 服务器,则我们可以在浏览器中输入:http://192.168.1.130:8787/vnc.html?path=websockify/?token=test2,依次类推。

图 7:采用 token 方式进行 noVNC 登录远程桌面


Read Latest: