8小时用HTML5打造VNCViewer

8小时用HTML5打造VNCViewer,第1张

http://cnborn.net/blog/

另一个话题是ThoughtWorks徐昊带来的《8小时用HTML5打造VNCViewer》。这个分享非常精彩,其实现过程中的思考方式、使用的新技术都让人有醍醐灌顶的感觉。以下的记录由现场的笔记总结而来,比较粗略,难免有失误,还望大家指正。
http://cnborn.net/blog/ 
由于HTML5具备Canvas, WebSocket,所以萌生了使用HTML5来打造一个VNCViewer的想法。同时为这个项目设定目标:在12小时之内完成。

HTML5的定义

在HTML5之前,HTML这个概念仅指代用以描述数据的语意化文档标签。之前的W3C始终将HTML定位为单纯定义数据的标准,有意淡化BOM(Browser Objective Model)对象。而从HTML5开始,第一次将HTML的概念扩展到HTML+CSS3+JS的集合。在原先的数据表现上添加了一些新的语意化标签如<header>, <footer>等,但BOM的增强更令人兴奋:引入Canvas, WebSQL, WebSocket(在频繁交互的网络应用中节约大量资源), PostMessage(在不同页面之间传递数据)等对象为实现更多种应用提供了可能。 

个人项目也要按照标准的项目流程做计划:进行任务分解。有任务分解列表的同时,也要有项目的风险列表。考虑到一些通常的项目风险,比如:一旦协议太复杂以致于不能用很短的时间了解,就会影响项目实现。

首先需要了解VNC协议,任务预计需要两小时。发现VNC的工作原理并不复杂:服务器和客户端经过握手确定协议版本、所支持的编码方式等,随后开始通信,传输屏幕上的显示内容。显示内容传输时支持不同编码方式,协议本身可以扩展以支持更多种编码方式。VNC的协议有43页(链接),1小时阅读完毕。其中主要包括两大部分,显示和接受输入。出于应用需要,不考虑输入部分的实现。

此时任务列表更新为:

  • 建立连接
  • 服务器与客户端间进行握手
  • 开始传送数据

使用HTML5的WebSocket建立连接时,发现WebSocket要求需要HTTP协议才能建立连接;同时建立长连接还需要如下步骤:HTML5端会发送一个请求,询问服务器是否能将协议升级成为WS/WSS协议,服务器需回复确认。但VNC服务器诞生较早,不支持升级协议这个约定。有两种解决方法:自己实现一个VNC Server,或者写一个Proxy来解决问题。因为自己实现VNC Server成本太高,不可能在时间限制内完成,所以选择了写Proxy的方案。
Proxy使用node.js , 一个运行在服务器端的JavaScript框架来完成。起初选用的原因主要还是个人的兴趣,接下来可以看到,最终这个框架拯救了整个项目。这个Proxy只用了10行JavaScript,使服务器和客户端的两个TCP流对接上即可。

服务器端代理部分耗时45分钟

接下来面临的是编码问题,VNC使用底层数据编码,而HTML端是相对高层的数据编码方式,这里通过node.js实现统一;服务器建立连接需要认证,VNC的认证机制使用DES加密。在网上寻找JavaScript DES库的时候,发现能找到的三个库均不能正常工作。不得已自己实现了JavaScript的DES库,耗费了不少时间。此时5个小时过去了,服务器端和客户端已经可以正确连接。

接下来解决显示的问题

Canvas有一个绘制函数几乎可以原生支持VNC的Raw编码方式,于是直接使用这个方法实现。测试时发现基本不能正常使用:由于数据传输量非常大,客户端的性能完全不能满足需求,画图速度太慢,占用资源过高。

6个小时过去了

考虑在信息传输方式上做优化,传递每个像素数据的Raw编码方式所需数据量过大。同时实验中发现不同VNC服务器发送信息的行为不太一样:苹果的服务器按照行的方式发送屏幕显示数据,而某个版本Linux中则是直接把屏幕分为四个区域来处理显示更新。按照区块刷新的编码方式进行了测试,发现并不能解决问题:画面后面的帧显示比原先略快但仍不可用,并且显示第一帧画面的速度非常慢。

解决传输数据量的问题,需要从传输协议上入手。VNC协议默认有5种Encode方式,分别是:

  • 全屏更新
  • 区域刷新
  • Hextile(将屏幕分成16x16的诸多小块来进行刷新,详解)
  • zlib 将raw的数据进行压缩然后再传输
  • hextile+zlib,将Hextile格式的数据进行压缩再传输

参考一些资料,均推荐使用zlib方式对数据进行压缩处理,可以节省带宽、提高速度(未经压缩的画面一帧的流量是4.3M)。此时需要一个JavaScript的zlib实现来进行解码工作。发现没有这样的库...... 此路不通。

能否使用HTML5的Worker进行后期处理?查阅文档发现Worker进程不能直接访问DOM对象,所以不能在Canvas上面进行绘画。而且传递大数据量时速度很慢。简单地说这个功能适用于计算密集的任务,但不适合这种数据密集的任务。

最后解决问题的关键功能,是一个比较陈旧、平时几乎不再使用的浏览器功能 - DataURI Encoding。即把资源经由Base64编码后直接显示在页面中。这里面最重要的突破在于:从最终目的中思考,用户最终的目的是什么?所需的VNC解码内容和哪些浏览器支持的原生信息格式最为接近?
首先想到的答案是视频,但是发现如果使用HTML5的<video>标签需要把VNC流转换为视频格式。这个工作太复杂,几乎无法完成。
如果不能作为视频来处理的话,那么作为图片显示的方式是否可行呢?把VNC的数据流转化为图片,浏览器即可通过硬件加速来显示图片。将VNC流转换成相应的图片格式在客户端进行太复杂,同时非常消耗资源。这时之前在服务器端选用的node.js技术发挥了重要作用。在VNC服务器端编写了一个新的VNC编码方式,可以直接将VNC的数据流以JPEG的方式进行编码(解决了传输数据量的问题),然后在服务器的node.js端对数据流进行解码,直接向浏览器传回通过Base64编码的JPEG图片,即可做到以很低的延迟显示VNC服务器的内容。

至此,整个项目完成,共耗时8小时23分钟

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/2086627.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-07-22
下一篇 2022-07-22

发表评论

登录后才能评论

评论列表(0条)

保存