HTML 5 案例研究:使用 WebSockets、Canvas 与 JavaScript 构建 noVNC 客户端

阅读数:5848 2010 年 7 月 6 日

话题:Java.NETRubyJavaScript架构HTML5语言 & 开发

noVNC是个 VNC 客户端,采用 HTML 5 WebSockets、Canvas 和 JavaScript 实现。近日,InfoQ 有幸采访到了 Joel Martin 以了解 noVNC 及其在HTML 5应用开发上的经验:

InfoQ:Joel,能否谈谈 noVNC 的整体架构,各个组件是如何搭配到一起的?

Joel:noVNC 的架构主要由以下 6 个组件构成:

  • 核心的 VNC/RFB 实现:该组件封装了所有的 RFB 协议相关的内容,是驱动其他组件的主要状态机。
  • Canvas 抽象:该组件为 HTML5 canvas API 提供了一个抽象,还会进行 Canvas 特性检测,对于没有完整支持 HTML5 canvas 规范或是实现有问题的浏览器,组件会采取其他一些办法解决这个问题。
  • 用户界面:封装了所有的 HTML DOM 交互(除了 canvas)。该组件会渲染页面控件,如连接 / 断开连接按钮、设置以及状态反馈。noVNC 的一个设计目标就是要能轻松加到现有的套件当中,因此该组件是可选的。
  • 辅助功能:包含了 noVNC 所用的一些杂项功能与扩展,包括对 JavaScript 数组的扩展(使之可以当作队列使用)、跨浏览器的事件处理以及调试与日志等。我还会从其他一些资源中引入一些 JavaScript 库以处理 base64 编解码和 DES 加密(用于 VNC 认证)。
  • WebSockets 回退:现在的大多数浏览器都没有本地的 WebSockets 支持,因此我为这些浏览器添加了一个Flash(Flex)仿真器,使用 WebSockets 加密技术扩展了最初的项目。
  • WebSockets 到 TCP 的代理:WebSockets 标准并非纯粹的 TCP socket 实现。标准中有类似于 HTTP 的握手以建立初始连接,接下来的每一帧都以 0 字节开始,255 字节结束。在 VNC 服务器开始支持 WebSockets 前( 我很希望能做到这一点),我们还是需要代理在 WebSockets 和标准的 TCP sockets 之间进行转换。我已经实现了一个通用代理(有 Python 和 C 两个版本),这对于那些从事着 WebSockets 开发的人来说有一定的帮助作用。

InfoQ:在开发 HTML5 应用时遇到的挑战主要有哪些?开发者需要提防哪些陷阱呢?

Joel:主要的挑战在于对那些缺乏 HTML5 特性以及只支持部分 HTML5 特性、甚至连部分特性都支持不好的浏览器提供回退支持。比如说,虽然 Chrome 5 和 Safari 5 都提供了本地的 WebSockets 支持,但当前版本的 Firefox 和 Opera 则不支持。一些老版本的浏览器也没有提供 canvas 像素操纵 API(更糟的是,有的浏览器虽然提供了支持,但一使用 Arora 0.5 就崩溃了)。已发布的各个版本的 Internet Explorer 都没有内置 WebSockets,甚至连最基本的内置 canvas 支持都没有(IE 9 Preview 开始提供 canvas 支持)。另一个挑战在于跨越多个浏览器的性能优化问题。每个浏览器都有不同的性能特质,在同一浏览器的不同版本中这一点也不尽相同(甚至同一个浏览器的不同操作系统版本也不一样)。只有很少的地方需要使用到浏览器检测技术,但对于性能优化问题,我觉得浏览器检测技术是必不可少的。

InfoQ:你都使用了哪些工具?目前的开发工具足以承担起构建 HTML5 应用的重任么?你希望今后能出来哪些新工具呢?

Joel:我的开发环境非常精简,使用 vim(加上很多扩展)在 Linux 上编写代码。频繁使用 firefox 上的 firebug 和 Chrome 中内置的开发者工具进行调试与分析。我还使用了 Crockford 的 JSLint 以保持 JavaScript 代码的整洁性。

我希望 firebug 与 Chrome 中的分析工具能给出比函数级别粒度更细的反馈信息,能告诉我们哪部分代码对垃圾收集产生了重要影响。现在 noVNC 代码还在不断优化,垃圾收集器已经成为一个主要的性能瓶颈,我开始深入到其中解决问题了。

我希望出来的新工具是代码分析器(就像 JSLint 那样),可以扫描 Javascript 代码基并生成好看的浏览器支持表格。我期望的输出形式是这样的:上面是代码中所用的特性列表,左边则是主要的浏览器与版本号。接下来,每个单元格就会报告代码使用特性的方式是否为给定的浏览器 / 版本所支持。虽说这么做并不会导致不同浏览器上代码测试的工作量,但毫无疑问,它有助于我们在开发过程中了解是否已经偏离了轨道。在理想情况下,扫描器还应该检测出 Javascript 是否针对某个特性使用了恰当的检测 / 问题解决办法。

InfoQ:对于目前的规范与实现来说,要克服的局限性主要有哪些呢?

Joel:值得庆幸的是规范做的很棒。

RFB(VNC)协议的文档在这里http://tigervnc.org/cgi-bin/rfbproto

这个站点提供了很好的 Javascript 参考信息(包括哪个浏览器版本支持哪些特性):http://www.hunlock.com/

我发现一个非常棒的站点,里面归纳了哪些浏览器支持哪些特性(涵盖了 HTML5 等内容),网址是http://caniuse.com/。站点http://quirksmode.org更是无价之宝(这就是著名的 PPK 站点,他是知名的 JavaScript 图书 PPK on JavaScript 的作者——译者注),详尽列出了哪些浏览器支持哪些 API 以及如何解决众多的限制。我要克服的最困难的浏览器限制就是缺乏本地的跨浏览器 WebSockets 支持。这是最近才出来的标准,还处在变更当中,但很多浏览器都纷纷采用了该标准。目前 webkit 支持该标准,因此 Chrome 5 和 Safari 5 都支持,不久之后 iPhone 也会支持。firefox 4 可能也会加入对其的支持。当然了,Opera 也会在不久的将来支持它。最大的问题在于 IE 9 是否会支持。

如前所述,我使用 Flash WebSockets 仿真器来支持那些没有本地支持的浏览器。扩展、修复以及解决 Flash(ActionScript)代码中的 bug 是个艰巨的任务。桥接 Javascript 和 Flash 也是个让人头疼的问题。Adobe 提供了 FABridge(仿真器使用到了),但这个桥太慢、太笨重,难以调试。

听说 IE 9 将提供完整(速度也很快)的 canvas 支持后我感到兴奋异常,但我还得解决旧版本 IE 缺乏本地 canvas 支持这个局限性,因为 IE 用的实在是太多了。现在有两个办法,一个是 explorercanvas,另一个是 fxcanvas。前者是个 JavaScript 库,它基于 IE 的 VML 支持创建了一个 canvas API;后者则是个 canvas 的 Flash 实现,但这两个办法都不是十全十美的。Explorercanvas 不支持像素操纵(这是因为 VML 是矢量而非光栅),而 fxcanvas 则提供了一个类似于 canvas 的 API,它存在一些严重的异步处理问题。遗憾的是,相对于其他支持 canvas 模拟的浏览器来说,IE 6、7 和 8 中的 JavaScript 引擎太慢了,这两个办法都没法很好地应用到 IE 上,现在我只能期望人们使用 Chrome Frame 了。

InfoQ:关于 noVNC 项目,未来的计划如何?

Joel:现在,我感觉最兴奋的事情就是能与一些 QEMU/KVM 开发者们(包括一个 Google 编码之夏的学生)一起工作来设计新的 VNC 编码器,新的编码器针对浏览器渲染进行了大量的优化,这个新的 VNC/RFB 编码器会以 PNG 格式传输图像数据。除了极佳的无损图像压缩外(相对于紧密编码来说),浏览器几乎不需要什么解码工作就能渲染 PNG 数据流(这一点与紧密压缩大不相同)。

WebSockets 到 TCP sockets 代理的需求对于 noVNC 的普及是个障碍,我希望 VNC 服务器能加入 WebSockets 支持,现在我的主要精力都放在了 libvncserver(用于构建不同的 VNC 服务器)和 QEMU/KVM 上,但还是希望能帮助并鼓励其他的 VNC 服务器开发者增加对 WebSockets 的支持。将 WebSockets 支持加到其他的 VNC 客户端用处也很大,因为 WebSockets 协议设计之初就考虑到支持的方便性并且可由 Web 服务器代理(因此会有兼容于 HTTP 的握手)。这将有助于解决 VNC 的一个老大难问题:与防火墙的交互。

之所以把这个项目命名为“noVNC”,一个原因是我还希望出现其他的“虚拟网络计算机”协议的实现,比如 RDP、NX 以及 Red Hat 的 Spice 协议。

如果 iPhone 能增加本地的 WebSockets 支持(显然 Flash 的回退已经超出了问题本身),我就会让 noVNC 运行在 iPhone 之上。我想增加的一个非常有用的特性是视角与缩放支持,这对于智能手机来说也非常关键。对于 Google 来说,如果能在 Android 上支持 noVNC 将是一件多么美妙的事情啊。

Guacamole 项目也采取了类似的处理方式,它同样是一个 HTML5 VNC 查看器,利用了服务器端的代理,它使用 Java 编写。目前版本的响应速度号称可以达到 VNC 的水平,只要浏览器支持 HTML5 canvas 标签就可以使用 Guacamole。

感兴趣的读者可以在 InfoQ 上找到关于HTML5RIA的更多信息!

查看英文原文:HTML5 Case Study: Building the noVNC Client with WebSockets, Canvas and JavaScript