版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、开源远程控制RealVNC源代码中的通讯协议RFB(远程帧缓冲) - 一分类: 远程控制 业余研究 开源软件2014-05-27 18:04 2040人阅读 评论(1) 收藏 举报 在网上流传的gh0st3.6源代码中,远程桌面总是存在CPU占用率高和画面更新不及时等问题。于是想到了著名的开源远程控制RealVNC 它采用了远程帧缓存的协议(Remote Frame buffer)
2、 在网上找到的一段关于RFB的描述 RFB 是真正意义上的“瘦客机”协议。RFB协议设计的重点在于减少对客户端的硬件需求。这样客户端就可以运行在许多不同的硬件上,客户机的任务实现上就会尽量的简单。RFB协议对于客户端是无状态的。也就是说:如果客户端从服务器端断开,那么如果它重新连接相同的服务器,客户端的状态会被保存。甚至,一个不同的客户端可以用来连接相同的RFB服务器。而在新的客户端已经能够获得与前一个客户端相同的用户状态。因此,用户的应用接口变的非
3、常便捷。只要合适的网络连接存在,那么用户就可以使用自己的应用程序,并且这些应用会一直保存,即使在不同的接入点也不会变化。这样无论在哪,系统都会给用户提供一个熟悉、独特的计算环境。显示协议显示协议是建立在“把像素数据放在一个由x,y 定位的方框内”这单一图形基础之上的。乍一看上去,把这么多的用户接口组件绘制出来是非常低效的方法。但是,允许不同的像素数据编码方式,使得我们在处理不同的参数(如:网络带宽,客户端的绘制速度,服务器处理速度)有了很大程度的灵活性。通过矩形的序列来完成帧缓存的更新。一次更新代表着从一个可用帧缓存状态转换到另一个可用,因此有点和视频的桢类似。尽管矩形的更新一般是分开的,但是
4、并不是必须的。显示协议的更新部分是由客户端通过命令驱动的。也就是说,更新只是在服务器端响应客户端的请求时发生的。这样就让协议更新质量是可变的。客户端/网络越慢,更新速度也就越慢。对于一些应用来说,相同区域的更新是连续不断的。如果用一个慢的客户端,那么帧缓存的缓存状态是可以被忽略的。这样也可以减少对客户端网络速度和绘制速度的要求。输入协议输入协议是基于标准工作站的键盘和鼠标等设备的连接协议。输入事件就是通过把客户端的输入发送到服务器端。这些输入事件也可以通过非标准的I /O 设备来综合。例如,手写笔引擎可能产生一个键盘事件。像素数据的表示初始的交互涉及到RFB客户端和服务器之间传输像素数据格式和
5、编码方式的协调。这种协调被设计的让客户端的工作尽量简单。而设计的底线是:服务器必须按照客户端的要求格式来提供像素数据。如果客户端可以同样的处理多种数据格式或编码格式,那么一般会选择服务器端易于生成的格式。像素格式涉及如何通过像素值来实现不同颜色的重现。最常用的一般像素格式是24 位或16 位的“真彩色”,它通过位来直接实现像素值到红、绿、蓝亮度的转换。8 位“颜色映射”可以任意映射像素值到RGB亮度的转换。编码指一个矩形的像素数据如何通过网线传输。每个像素数据的矩形都加上了一个头,给定矩形在屏幕上的X、Y坐标、矩形的宽和高,以及指定的编码类型。而后数据本身就是采用这种特定的编码方式。数据本身遵
6、循特定的编码。目前的编码方式主要有Raw、CopyRect、RRE、Hextile 和ZRLE.在实际应用中我们一般使用ZRLE、Hextile 和CopyRect,因为它们提供了典型桌面的最好压缩。其他可能的编码方式还包括,用于静态图片的JPEG和用于动态图像有效传输的MPEG。协议可以通过增加新的编码方式来进行扩展。协议扩展协议可以通过以下方式进行扩展:新的编码方式一种新的协议可以通过与现存的客户端和服务端进行相关兼容的添加。因为现存的服务器将会忽略它们所不支持的新编码方式。所以客户端通过新的编码方式进行请求也就不会有结果返回。伪编码方式除了真正的编码方式,客户端也可以请求“伪编码”通告服
7、务器,它支持某一协议的扩展。服务器如果不支持这种扩展,那么它将忽略。值得注意的是:客户端必须先假设服务器端不支持这种扩展,直到它获得服务器端支持的确认。新的安全方式添加一个新型的安全方式会带来无限的灵活性,它通过修改协议的一些行为,但是并没有牺牲现存客户端和服务器端的兼容性。客户端和服务器端可以通过协议好的安全方式进行交流,当然并不一定与RFB协议类似。无论如何你都不应使用不同的版本号。RFB协议的版本是由RealVNC公司来制定的。如果你使用一个不同的协议版本可能与RFB/VNC不兼容,要保证协议的兼容性,请联系RealVNC公司。这样会减少在编码方式和安全类型上的冲突。协议消息RFB协议可
8、以进行可靠的传输,如字节流或基于消息的。和大多数协议一样,它也是通过TCP /IP协议簇连接。协议由三步完成连接。首先是握手报文,目的是对协议版本和加密方式进行协商。第二步是初始化报文,主要用于客户和服务器的初始化消息。最后就是正常协议的交互,客户端可以按需发送消息,然后可以获得服务器的回复。所有的消息以消息类型开始,接下来是特定的消息数据。协议消息描述的基本类型有:U8、U16、U32、S8、S16、S32。U表示无符号整数,S表示有符号整数。所有字节整数(除了像素值本身)遵从big endian顺序。big endian或者little endian跟cpu有关,从而影响整数在内存中的排列
9、顺序。big endian是高字节在前,little endian是低字节在前,网络字节序一般是big-endian。PIXEL代表一个像素值bytesPerPixel字节,8XbytesPerPixel = bits-per-pixelRealVNC 分为客户端和服务端客户端名为 VNCViewer 服务端名为 VNC客户端连接到服务器端这时候 服务端 会给 客户端发送当前提供最大支持的版本号。cpp view plaincopyprint?1. /初始化RFB协议 2. void SConnection:initialiseP
10、rotocol() 3. 4. cp.writeVersion(os); 5. state_ = RFBSTATE_PROTOCOL_VERSION; 6. 7. /写入版本 8. void ConnParams:writeVersion(rdr:OutStream* os) 9.
11、;10. char str13; 11. sprintf(str, "RFB %03d.%03dn", majorVersion, minorVersion); 12. os->writeBytes(str, 12); 13. os->flush()
12、; 14. 这里对应的发送的内容如下00000000 52 46 42 20 30 30 33 2E 30 30 38 0A RFB 003.008.发送数据长度
13、12 发送数据内容 RFB 003.008此时VNC 的数据处理状态为 RFBSTATE_PROTOCOL_VERSION2.viewer收到来自vnc的版本号信息因为viewer在init()函数中已经设置数据处理状态为 RFBSTATE_PROTOCOL_VERSIONcpp view plaincopyprint?1. void CConnection:initialiseProtocol() 2. 3.
14、;state_ = RFBSTATE_PROTOCOL_VERSION; 4. cpp view plaincopyprint?1. void CConnection:processMsg() 2. 3. switch (state_) 4. 5. case
15、;RFBSTATE_PROTOCOL_VERSION: 6. processVersionMsg(); 7. break; 8. case RFBSTATE_SECURITY_TYPES:
16、 9. processSecurityTypesMsg(); 10. break; 11. case RFBSTATE_SECURITY: 1
17、2. processSecurityMsg(); 13. break; 14. case RFBSTATE_SECURITY_RESULT: 15. &
18、#160;processSecurityResultMsg(); 16. break; 17. case RFBSTATE_INITIALISATION: 18. processInitMsg(); &
19、#160; 19. break; 20. case RFBSTATE_NORMAL: 21. reader_->readM
20、sg(); 22. break; 23. case RFBSTATE_UNINITIALISED: 24. throw Exception("CConnection:processMsg:
21、160;not initialised yet?"); 25. default: 26. throw Exception("CConnection:processMsg: invalid state"); 27. 28.
22、160;cpp view plaincopyprint?1. 进入 processVersionMsg()函数 2. /处理 RFBSTATE_PROTOCOL_VERSION 3. void CConnection:processVersionMsg() 4. 5. vlog.debug("reading protocol version");
23、;6. bool done; 7. /这里读取服务器版本,如果读取失败 数据处理状态切换为 RFBSTATE_INVALID 8. if (!cp.readVersion(is, &done) 9. 10.
24、160;state_ = RFBSTATE_INVALID; 11. throw Exception("reading version failed: not an RFB server?"); 12. 13. /读取失败 返回 14
25、. if (!done) 15. return; 16. 17. ("Server supports RFB protocol version %d.%d", 18.
26、160; cp.majorVersion, cp.minorVersion); 19. 20. / The only official RFB protocol versions are currently 3.3, 3.7 and 3.8 21.
27、 /如果RFB版本号低于 3.3 不支持。数据处理状态切换为 RFB_INVALID 抛出异常 22. if (cp.beforeVersion(3, 3) 23. 24. char msg256; 25.
28、160; sprintf(msg, "Server gave unsupported RFB protocol version %d.%d", 26. cp.majorVersion, cp.minorVersion); 27.
29、 vlog.error(msg); 28. state_ = RFBSTATE_INVALID; 29. throw Exception(msg); 30.
30、31. else if (useProtocol3_3 | cp.beforeVersion(3, 7) 32. 33. cp.setVersion(3, 3); 34. 35.
31、160; else if (cp.afterVersion(3, 8) 36. 37. cp.setVersion(3, 8); 38. 39. /这里写入版本号信息 40. cp.w
32、riteVersion(os); 41. /Viewer切换数据处理状态 RFBSTATE_SECURITY_TYPES 42. state_ = RFBSTATE_SECURITY_TYPES; 43. 44. ("Using RFB protocol version %d.%d",
33、0;45. cp.majorVersion, cp.minorVersion); 46. 47. /向服务器发送版本号 48. void ConnParams:writeVersion(rdr:OutStream* os) 49. 50. char str13; 51.
34、0; sprintf(str, "RFB %03d.%03dn", majorVersion, minorVersion); 52. os->writeBytes(str, 12); 53. os->flush(); 54. 这个函数发送的内容00000000 &
35、#160;52 46 42 20 30 30 33 2E 30 30 38 0A RFB 003.008.长度为 12 个字节这时候 VNCViewer的数据处理状态为 RFBSTATE_SECURITY_TYPES
36、; 3.vnc收到来自viewer的版本信息因为VNC当前的数据处理状态是 RFBSTATE_PROTOCOL_VERSION所以会进入processVersionMsg()函数处理viewer发送过来的版本信息 cpp view plaincopyprint?1. /处理 RFBSTATE_PROTOCOL_VERSION 2. void SConnection:processVersionMsg() 3. 4.
37、160; vlog.debug("reading protocol version"); 5. bool done; 6. /读取来自viewer的版本号 7. if (!cp.readVersion(is, &done) 8. 9.
38、0; state_ = RFBSTATE_INVALID; 10. throw Exception("reading version failed: not an RFB client?"); 11.
39、60;12. if (!done) 13. return; 14. 15. ("Client needs protocol version %d.%d",cp.majorVersion, cp.minorVersion);
40、0; 16. 17. if (cp.majorVersion != 3) 18. 19. / unknown protocol version 20.
41、;char msg256; 21. sprintf(msg, "Error: client needs protocol version %d.%d, server has %d.%d",cp.majorVersion, cp.minorVersion,defaultMajorVersion, defaultMinorVersion);
42、160; 22. throwConnFailedException(msg); 23. 24. 25. if (cp.minorVersion != 3 && cp.minorVersion != 7 &&
43、;cp.minorVersion != 8) 26. 27. vlog.error("Client uses unofficial protocol version %d.%d",cp.majorVersion, cp.minorVersion); 28.
44、60; if (cp.minorVersion >= 8) 29. cp.minorVersion = 8; 30. else if (cp.minorVersion
45、160;= 7) 31. cp.minorVersion = 7; 32. else 33. cp.minorVersi
46、on = 3; 34. vlog.error("Assuming compatibility with version %d.%d",cp.majorVersion, cp.minorVersion); 35. 36. 37.
47、;versionReceived(); 38. 39. /这里是获取到加密类型 40. std:list<rdr:U8> secTypes; 41. std:list<rdr:U8>:iterator i; 42. securityFactory->getSecTypes(&
48、;secTypes, reverseConnection); 43. 44. if (cp.isVersion(3, 3) 45. 46. / cope with legacy 3.3 client only if&
49、#160;"no authentication" or "vnc 47. / authentication" is supported. 48. for (i = secTypes.begin(); i !=
50、60;secTypes.end(); i+) 49. 50. if (*i = secTypeNone | *i = secTypeVncAuth) 51.
51、60; break; 52. 53. if (i = secTypes.end() 54.
52、160; 55. char msg256; 56. sprintf(msg, "No supported security type for %d.%d client
53、", 57. cp.majorVersion, cp.minorVersion); 58. throwConnFailedException(msg); 59.
54、160; 60. 61. os->writeU32(*i); 62. if (*i = secTypeNone) 63.
55、160; os->flush(); 64. state_ = RFBSTATE_SECURITY; 65. security = securityFactory->getSSecurity(*i, reverseConnection);
56、0; 66. processSecurityMsg(); 67. return; 68. 69. 70. / list supported security types&
57、#160;for >=3.7 clients 71. if (secTypes.empty() 72. throwConnFailedException("No supported security types"); 73. 74.
58、;os->writeU8(secTypes.size(); 75. for (i = secTypes.begin(); i != secTypes.end(); i+) 76. os->writeU8(*i); 77. os->flush();
59、0; 78. state_ = RFBSTATE_SECURITY_TYPE; 79. 80. 这个函数主要是 81. a.验证RFB版本号 82. b.获取到加密类型 83. c.发送加密类型到VncViewer 84. d.设置数据处理标志为 RFBSTATE_SECURITY_TYPE 4.vncViewer状态为RFBSTATE_SE
60、CURITY_TYPES 收到vnc发送过来的加密类型后执行processSecurityTypesMsg()cpp view plaincopyprint?1. void CConnection:processSecurityTypesMsg() 2. 3. vlog.debug("processing security types message");
61、0; 4. 5. int secType = secTypeInvalid; 6. 7. if (cp.isVersion(3, 3) 8. 9. 10.
62、160;/ legacy 3.3 server may only offer "vnc authentication" or "none" 11. secType = is->readU32(); 12.
63、160;if (secType = secTypeInvalid) 13. 14. throwConnFailedException(); 15.
64、60; 16. else if (secType = secTypeNone | secType = secTypeVncAuth) 17. 18. &
65、#160; int j; 19. for (j = 0; j < nSecTypes; j+) 20. if (secTypesj =
66、60;secType) 21. break; 22. if (j = nSecTypes) 23.
67、0; secType = secTypeInvalid; 24. 25. else 26. &
68、#160; 27. vlog.error("Unknown 3.3 security type %d", secType); 28. throw Exception("Unknown
69、0;3.3 security type"); 29. 30. 31. 32. else 33. 34. &
70、#160; / >=3.7 server will offer us a list 35. int nServerSecTypes = is->readU8(); 36. if (nServerSecTypes =
71、0;0) 37. throwConnFailedException(); 38. 39. int secTypePos = nSecTypes; 40. &
72、#160;for (int i = 0; i < nServerSecTypes; i+) 41. 42. rdr:U8 serverSecType = is->readU8();
73、 43. vlog.debug("Server offers security type %s(%d)", 44. secTypeName(serverSecType),&
74、#160;serverSecType); 45. 46. / If we haven't already chosen a secType, try this one 47.
75、0; / If we are using the client's preference for types, 48. / we keep trying types, to find the one that
76、160;matches and 49. / which appears first in the client's list of supported types. 50.
77、 if (secType = secTypeInvalid | clientSecTypeOrder) 51. 52. for
78、0;(int j = 0; j < nSecTypes; j+) 53. 54.
79、 if (secTypesj = serverSecType && j < secTypePos) 55. 56.
80、 secType = secTypesj; 57. se
81、cTypePos = j; 58. break; 59.
82、; 60. 61. / NB: Continue reading the
83、;remaining server secTypes, but ignore them 62. 63. 64. 65.
84、/ Inform the server of our decision 66. if (secType != secTypeInvalid) 67. 68.
85、0; os->writeU8(secType); 69. os->flush(); 70. vlog.debug("Choosing security type
86、0;%s(%d)", secTypeName(secType), secType); 71. 72. 73. 74. if (secType = secTypeInvalid) 75.
87、; 76. state_ = RFBSTATE_INVALID; 77. vlog.error("No matching security types"); 78. throw
88、 Exception("No matching security types"); 79. 80. 81. state_ = RFBSTATE_SECURITY; 82. /因为这里没有开启认证,所以security返回的是一个CSecurityNone类 83.
89、0;security = getCSecurity(secType); 84. /调用getCSecurity函数进行下一步的认证工作 85. processSecurityMsg(); 86. 87. 88. CSecurity* CConn:getCSecurity(int secType) 89. 90. &
90、#160;switch (secType) 91. 92. case secTypeNone: 93. return new CSecurityNone(); 94. case secTypeVncAuth:
91、 95. return new CSecurityVncAuth(this); 96. default: 97. throw Exception("Unsupported secType?"); 98.
92、0; 99. 这个函数a.获取加密类型b.切换数据处理状态为 RFBSTATE_SECURITYC.生成用例处理加密的类 d.调用processSecurityMsg()函数继续处理加密cpp view plaincopyprint?1. void CConnection:processSecurityMsg() 2. 3. vlog.debug("processing&
93、#160;security message"); 4. if (security->processMsg(this) 5. 6. state_ = RFBSTATE_SECURITY_RESULT; 7.
94、0; processSecurityResultMsg(); 8. 9. 因为我这里没有开启认证,所以processMsg()函数直接返回TRUE就通过验证。如果开启了VNC验证,会执行这个函数cpp view plaincopyprint?1. bool CSecurityVncAuth:processMsg(CConnection* cc) 2. 3.
95、 rdr:InStream* is = cc->getInStream(); 4. rdr:OutStream* os = cc->getOutStream(); 5. 6. / Read the challenge & obtain the
96、0;user's password 7. rdr:U8 challengevncAuthChallengeSize; 8. is->readBytes(challenge, vncAuthChallengeSize); 9. PlainPasswd passwd; 10.
97、160;upg->getUserPasswd(0, &passwd.buf); 11. 12. / Calculate the correct response 13. rdr:U8 key8; 14. int pwdLen = strlen(passwd.bu
98、f); 15. for (int i = 0; i < 8; i+) 16. keyi = i < pwdLen ? passwd.bufi : 0; 17. deske
99、y(key, EN0); 18. for (int j = 0; j < vncAuthChallengeSize; j += 8) 19. des(challenge + j, challenge + j); 20.
100、160; 21. / Return the response to the server 22. os->writeBytes(challenge, vncAuthChallengeSize); 23. os->flush(); 24. return
101、 true; 25. 认证通过后数据处理状态切换为RFBSTATE_SECURITY_RESULT继续执行processSecurityResultMsg()函数cpp view plaincopyprint?1. void CConnection:processSecurityResultMsg() 2. 3. vlog.debug("processing security result
102、0;message"); 4. int result; 5. if (cp.beforeVersion(3, 8) && security->getType() = secTypeNone) 6. 7.
103、 result = secResultOK; 8. 9. else 10. 11. if (!is->checkNoWait(1) 12.
104、 return; 13. result = is->readU32(); 14. 15. switch (result) 16.
105、; 17. case secResultOK: 18. securityCompleted(); 19. return; 20. case secResultFailed:
106、0;21. vlog.debug("auth failed"); 22. break; 23. case secResultTooMany: 24. vlog
107、.debug("auth failed - too many tries"); 25. break; 26. default: 27. throw Exception("Unknown secu
108、rity result from server"); 28. 29. CharArray reason; 30. if (cp.beforeVersion(3, 8) 31. reason.buf
109、160;= strDup("Authentication failure"); 32. else 33. reason.buf = is->readString(); 34. state_ = RFBSTATE_INVALID; 35
110、. throw AuthFailureException(reason.buf); 36. 验证通过执行securityCompleted()函数cpp view plaincopyprint?1. void CConnection:securityCompleted() 2. 3. state_ = RFBSTATE_INITIALISATION;
111、; 4. reader_ = new CMsgReaderV3(this, is); 5. writer_ = new CMsgWriterV3(&cp, os); 6. vlog.debug("Authentication success!"); 7.
112、60; authSuccess(); 8. writer_->writeClientInit(shared); 9. 设置 vncViewer的数据处理状态为 RFBSTATE_INITIALISATION 创建CMsgReaderV3类用于读取创建CMsgWriterV3类用于写入调用 writeClientInit 函数cpp view plaincopyprint?1. vo
113、id CMsgWriterV3:writeClientInit(bool shared) 2. 3. /是否分享屏幕 默认为false 4. os->writeU8(shared); 5. endMsg(); 6. 7. void CMsgWriterV3:endMsg() 8.
114、60;9. os->flush(); 10. 这里,viewer数据处理状态为 RFBSTATE_INITIALISATION 所以这个函数发送了两次数据第一次是发送加密类型 os->writeU8(secType)第二次是发送的屏幕是否共享 os->writeU8(shared);发送数据内容5. vnc当前状态为 RFBSTATE_SECURITY_TYPE
115、调用processSecurityTypeMsg函数来处理Viewer的数据 cpp view plaincopyprint?1. /RFBSTATE_SECURITY_TYPE 2. void SConnection:processSecurityTypeMsg() 3. 4. vlog.debug("processing security type message"); 5.
116、 /第一次是读取 加密类型 6. int secType = is->readU8(); 7. 8. / Verify that the requested security type should be offered 9. s
117、td:list<rdr:U8> secTypes; 10. std:list<rdr:U8>:iterator i; 11. securityFactory->getSecTypes(&secTypes, reverseConnection); 12. for (i = secTypes.b
118、egin(); i != secTypes.end(); i+) 13. if (*i = secType) 14. break; 15.
119、 if (i = secTypes.end() 16. throw Exception("Requested security type not available"); 17. 18. ("Client requests security type %s(%d)",secTypeName(secType), secType); 19. 20. try 21.
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 安全检查服务合同范本
- 冀少版八年级生物上册第三单元第三节无机盐与植物的生长课件
- 学前教育进入“有专门法可依”新阶段
- 部编本二年级上册语文第四至七单元(内容含课文口语交际及语文园地)全部教案
- 七年级下册古诗文预习《爱莲说》-2022-2023学年七年级语文古诗文寒假复习预习课
- 消防安全群防群治实施细则
- 人教版新课标小学数学四年级下册教案
- 医疗行业专业劳务派遣方案
- 石油勘探设备校正操作规程
- 电力工程投标诚信承诺书模板
- 陶艺教学课件
- 商务星球版七年级上册地理知识点归纳总结
- 主播试用期合同模板正规范本(通用版)
- 悦纳自我向阳而生心理健康教育主题班会课件
- 艾略特的诗 中英
- 天棚抹灰施工方案施工方案
- 《高炉炉顶均压煤气及休风煤气回收技术要求》
- 专题1.2 绝对值的综合(压轴题专项讲练)2023-2024学年七年级数学上册压轴题专项讲练系列(人教版)(解析版)
- 桥式起重机培训资料
- 低碳生活与绿色文明智慧树知到课后章节答案2023年下华南农业大学
- 大学生心理健康教育智慧树知到课后章节答案2023年下安徽中医药大学
评论
0/150
提交评论