(文章是基于刚刚做过的一个项目,对相关知识点进行总结回顾。主要内容均是对之前收集资料的总结概括,很多内容转载自其它地方。因为时间比较长,没有一一记录转载地址,特此感谢!)
一、简介
RFB(远程帧缓冲)是一个用于远程访问图形用户接口的简单协议。适用于所有的桌面系统和应用,包括X11,Windows和Macintosh等。
RFB是基于tcp的一个应用层协议。
我们把用户所在的一端(包括显示器、键盘和鼠标)被称为RFB客户端。而帧缓冲发生变化的一端(桌面系统和应用)称为RFB服务器。
RFB协议是一个瘦客户协议。协议设计的重点是减小对客户端的要求。这样,客户端可以运行在多种范围的硬件上,实现的任务是使客户端尽可能地简单。
RFB协议也使得客户端是“无状态”的。如果一个客户端和服务器断开了连接,稍后再一次连接到这台服务器上,用户的会话不会被关闭,状态会一直保持着。不同的客户端可以连接到同一个服务器上,在新的客户端上用户看到的是和原来的客户端上相同的图形用户接口。这样,用户的桌面变的完全可移动了。只要有合适的网络连接,用户就可以访问他个人的桌面应用,不论他走到哪里都可以连接到自己的会话上,而这些应用的状态可以一直保持着。
二、显示协议
RFB协议的显示部分基于一个简单的画图原理:“将一个矩形块的象素点放在给定位置(x,y)上”。这样做初看起来也许非常低效,因为要将用户所有的图形组件都画出来。但是由于可以为象素数据进行多种不同的编码,可以根据不同的参数比如网络带宽、客户端计算速度和服务器处理的速度等选择灵活的编码方式。一系列的矩形块组成了一个帧缓冲更新。一个更新描述了帧缓冲从一个状态到另一个状态的变化情况,所以,某些方面,这和音频的帧很类似。
更新协议是客户端“命令-驱动”型的。即服务器只有在收到客户端的请求才向其发送更新。这使得显示协议的质量可以调整。客户端和网络速度越慢,更新率就会越低。对于典型的应用,帧缓冲上相同区域的更新往往非常频繁。如果客户端或者网络非常慢,由于非常低的网络传输和客户端更新,帧缓冲上瞬时的状态都可以被忽略掉。
三、输入协议
输入协议是基于键盘和多键鼠标设备的标准工作站模型。当用户敲了一下键盘或者鼠标,或者移动了一下鼠标,客户端把这些输入事件简单地传送给服务器。输入事件可以由其它非标准I/O设备产生,如笔形手写板引擎也可以生成键盘事件,之后服务端对事件进行相应处理。事件按照RFB协议规定的格式进行发送即可。
四、象素数据的表示
RFB客户端和服务器最初的交互包括协商将要传输的象素数据的格式和编码类型。协商被设计成使客户端的工作尽可能的简单。底线是服务器必须可以一直提供客户端想要的象素数据的格式。但是如果客户端可以处理多种编码类型,它会选择对服务器来说最容易生成的编码。
象素格式是指象素值颜色表示法 最常用的象素格式是24位或16位真彩色。,它通过位来直接实现像素值到红、绿、蓝亮度的转换。8 位“颜色映射”可以任意映射像素值到RGB亮度的转换。
编码是指怎样通过网络把矩形象素点的数据发送出去。每一个矩形象素点的数据被加了一个前缀包括它在屏幕上的位置,矩形象素点的宽度和高度,以及一个“编码类型”来描述该象素的编码方式。然后是经过编码的数据本身。
目前的编码方式主要有Raw、CopyRect、RRE、Hextile 和ZRLE.在实际应用中我们一般使用ZRLE、Hextile 和CopyRect,因为它们提供了典型桌面的最好压缩。其他可能的编码方式还包括,用于静态图片的JPEG和用于动态图像有效传输的MPEG。协议可以通过增加新的编码方式来进行扩展。(编码的具体描述见其它文章)
五、协议扩展(添加新的编码方式)
协议可以通过以下方式进行扩展:
新的编码方式:
一种新的协议可以通过与现存的客户端和服务端进行相关兼容的添加。因为现存的服务器将会忽略它们所不支持的新编码方式。所以客户端通过新的编码方式进行请求也就不会有结果返回。
伪编码方式:
除了真正的编码方式,客户端也可以请求“伪编码”通告服务器,它支持某一协议的扩展。服务器如果不支持这种扩展,那么它将忽略。值得注意的是:客户端必须先假设服务器端不支持这种扩展,直到它获得服务器端支持的确认。
新的安全方式:
添加一个新型的安全方式会带来无限的灵活性,它通过修改协议的一些行为,但是并没有牺牲现存客户端和服务器端的兼容性。客户端和服务器端可以通过协议好的安全方式进行交流,当然并不一定与RFB协议类似。
无论如何你都不应使用不同的版本号。
RFB协议的版本是由RealVNC公司来制定的。如果你使用一个不同的协议版本可能与RFB/VNC不兼容,要保证协议的兼容性,请联系RealVNC公司。这样会减少在编码方式和安全类型上的冲突。
六、 协议消息
RFB协议可以进行可靠的传输,如字节流或基于消息的。和大多数协议一样,它也是通过TCP /IP协议簇连接。
协议由三步完成连接。
首先是握手报文,目的是对协议版本和加密方式进行协商。
第二步是初始化报文,主要用于客户和服务器的初始化消息。
最后就是正常协议的交互,客户端可以按需发送消息,然后可以获得服务器的回复。
所有的消息以消息类型开始,接下来是特定的消息数据。
协议消息描述的基本类型有:U8、U16、U32、S8、S16、S32。(U表示无符号整数,S表示有符号整数。)
所有字节整数(除了像素值本身)遵从big endian顺序。
不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序。 最常见的有两种: 1. Little-endian:将低序字节存储在起始地址(低位编址) 2. Big-endian:将高序字节存储在起始地址(高位编址) 例子1:在内存中双字0x01020304(DWORD)的 存储方式。 内存地址4000 4001 4002 4003 LE04030201 BE01020304 注:每个地址存1个字节,每个字有4个字节。2位16进制数是1个字节(0xFF=11111111)。 例子2:如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为
|
big endian或者little endian跟cpu有关,从而影响整数在内存中的排列顺序。big endian是高字节在前,little endian是低字节在前,网络字节序一般是big-endian。
PIXEL代表一个像素值bytesPerPixel字节,8XbytesPerPixel = bits-per-pixel。