版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、开源远程控制RealVNC源代码中的通讯协议RFB(远程帧缓冲) - 一分类:远程控制业余研究开源软件2014-05-27 18:042040人阅读评论(1)收藏举报 在网上流传的gh0st3.6源代码中,远程桌面总是存在CPU占用率高和画面更新不及时等问题。于是想到了著名的开源远程控制RealVNC 它采用了远程帧缓存的协议(Remote Frame buffer) 在网上找到的一段关于RFB的描述 RFB 是真正意义上的“瘦客机”协议。RFB协议设计的重点在于减少对客户端的硬件需求。这样客户端就可以运行在许多不同的硬件上,客户机的任务实现上就会尽量的简单。RFB协议对于客户端是无状态的。也
2、就是说:如果客户端从服务器端断开,那么如果它重新连接相同的服务器,客户端的状态会被保存。甚至,一个不同的客户端可以用来连接相同的RFB服务器。而在新的客户端已经能够获得与前一个客户端相同的用户状态。因此,用户的应用接口变的非常便捷。只要合适的网络连接存在,那么用户就可以使用自己的应用程序,并且这些应用会一直保存,即使在不同的接入点也不会变化。这样无论在哪,系统都会给用户提供一个熟悉、独特的计算环境。显示协议显示协议是建立在“把像素数据放在一个由x,y 定位的方框内”这单一图形基础之上的。乍一看上去,把这么多的用户接口组件绘制出来是非常低效的方法。但是,允许不同的像素数据编码方式,使得我们在处理
3、不同的参数(如:网络带宽,客户端的绘制速度,服务器处理速度)有了很大程度的灵活性。通过矩形的序列来完成帧缓存的更新。一次更新代表着从一个可用帧缓存状态转换到另一个可用,因此有点和视频的桢类似。尽管矩形的更新一般是分开的,但是并不是必须的。显示协议的更新部分是由客户端通过命令驱动的。也就是说,更新只是在服务器端响应客户端的请求时发生的。这样就让协议更新质量是可变的。客户端/网络越慢,更新速度也就越慢。对于一些应用来说,相同区域的更新是连续不断的。如果用一个慢的客户端,那么帧缓存的缓存状态是可以被忽略的。这样也可以减少对客户端网络速度和绘制速度的要求。输入协议输入协议是基于标准工作站的键盘和鼠标等
4、设备的连接协议。输入事件就是通过把客户端的输入发送到服务器端。这些输入事件也可以通过非标准的I /O 设备来综合。例如,手写笔引擎可能产生一个键盘事件。像素数据的表示初始的交互涉及到RFB客户端和服务器之间传输像素数据格式和编码方式的协调。这种协调被设计的让客户端的工作尽量简单。而设计的底线是:服务器必须按照客户端的要求格式来提供像素数据。如果客户端可以同样的处理多种数据格式或编码格式,那么一般会选择服务器端易于生成的格式。像素格式涉及如何通过像素值来实现不同颜色的重现。最常用的一般像素格式是24 位或16 位的“真彩色”,它通过位来直接实现像素值到红、绿、蓝亮度的转换。8 位“颜色映射”可以
5、任意映射像素值到RGB亮度的转换。编码指一个矩形的像素数据如何通过网线传输。每个像素数据的矩形都加上了一个头,给定矩形在屏幕上的X、Y坐标、矩形的宽和高,以及指定的编码类型。而后数据本身就是采用这种特定的编码方式。数据本身遵循特定的编码。目前的编码方式主要有Raw、CopyRect、RRE、Hextile 和ZRLE.在实际应用中我们一般使用ZRLE、Hextile 和CopyRect,因为它们提供了典型桌面的最好压缩。其他可能的编码方式还包括,用于静态图片的JPEG和用于动态图像有效传输的MPEG。协议可以通过增加新的编码方式来进行扩展。协议扩展协议可以通过以下方式进行扩展:新的编码方式一种
6、新的协议可以通过与现存的客户端和服务端进行相关兼容的添加。因为现存的服务器将会忽略它们所不支持的新编码方式。所以客户端通过新的编码方式进行请求也就不会有结果返回。伪编码方式除了真正的编码方式,客户端也可以请求“伪编码”通告服务器,它支持某一协议的扩展。服务器如果不支持这种扩展,那么它将忽略。值得注意的是:客户端必须先假设服务器端不支持这种扩展,直到它获得服务器端支持的确认。新的安全方式添加一个新型的安全方式会带来无限的灵活性,它通过修改协议的一些行为,但是并没有牺牲现存客户端和服务器端的兼容性。客户端和服务器端可以通过协议好的安全方式进行交流,当然并不一定与RFB协议类似。无论如何你都不应使用
7、不同的版本号。RFB协议的版本是由RealVNC公司来制定的。如果你使用一个不同的协议版本可能与RFB/VNC不兼容,要保证协议的兼容性,请联系RealVNC公司。这样会减少在编码方式和安全类型上的冲突。协议消息RFB协议可以进行可靠的传输,如字节流或基于消息的。和大多数协议一样,它也是通过TCP /IP协议簇连接。协议由三步完成连接。首先是握手报文,目的是对协议版本和加密方式进行协商。第二步是初始化报文,主要用于客户和服务器的初始化消息。最后就是正常协议的交互,客户端可以按需发送消息,然后可以获得服务器的回复。所有的消息以消息类型开始,接下来是特定的消息数据。协议消息描述的基本类型有:U8、
8、U16、U32、S8、S16、S32。U表示无符号整数,S表示有符号整数。所有字节整数(除了像素值本身)遵从big endian顺序。big endian或者little endian跟cpu有关,从而影响整数在内存中的排列顺序。big endian是高字节在前,little endian是低字节在前,网络字节序一般是big-endian。PIXEL代表一个像素值bytesPerPixel字节,8XbytesPerPixel = bits-per-pixelRealVNC 分为客户端和服务端客户端名为 VNCViewer服务端名为 VNC客户端连接到服务器端这时候 服务端 会给 客户端发送当前
9、提供最大支持的版本号。cppview plaincopyprint?1. /初始化RFB协议2. voidSConnection:initialiseProtocol()3. 4. cp.writeVersion(os);5. state_=RFBSTATE_PROTOCOL_VERSION;6. 7. /写入版本8. voidConnParams:writeVersion(rdr:OutStream*os)9. 10. charstr13;11. sprintf(str,RFB%03d.%03dn,majorVersion,minorVersion);12. os-writeBytes(st
10、r,12);13. os-flush();14. 这里对应的发送的内容如下00000000524642203030332E3030380ARFB003.008.发送数据长度12发送数据内容RFB003.008此时VNC的数据处理状态为RFBSTATE_PROTOCOL_VERSION2.viewer收到来自vnc的版本号信息因为viewer在init()函数中已经设置数据处理状态为RFBSTATE_PROTOCOL_VERSIONcppview plaincopyprint?1. voidCConnection:initialiseProtocol()2. 3. state_=RFBSTATE
11、_PROTOCOL_VERSION;4. cppview plaincopyprint?1. voidCConnection:processMsg()2. 3. switch(state_)4. 5. caseRFBSTATE_PROTOCOL_VERSION:6. processVersionMsg();7. break;8. caseRFBSTATE_SECURITY_TYPES:9. processSecurityTypesMsg();10. break;11. caseRFBSTATE_SECURITY:12. processSecurityMsg();13. break;14. ca
12、seRFBSTATE_SECURITY_RESULT:15. processSecurityResultMsg();16. break;17. caseRFBSTATE_INITIALISATION:18. processInitMsg();19. break;20. caseRFBSTATE_NORMAL:21. reader_-readMsg();22. break;23. caseRFBSTATE_UNINITIALISED:24. throwException(CConnection:processMsg:notinitialisedyet?);25. default:26. thro
13、wException(CConnection:processMsg:invalidstate);27. 28. cppview plaincopyprint?1. 进入processVersionMsg()函数2. /处理RFBSTATE_PROTOCOL_VERSION3. voidCConnection:processVersionMsg()4. 5. vlog.debug(readingprotocolversion);6. booldone;7. /这里读取服务器版本,如果读取失败数据处理状态切换为RFBSTATE_INVALID8. if(!cp.readVersion(is,&do
14、ne)9. 10. state_=RFBSTATE_INVALID;11. throwException(readingversionfailed:notanRFBserver?);12. 13. /读取失败返回14. if(!done)15. return;16. 17. (ServersupportsRFBprotocolversion%d.%d,18. cp.majorVersion,cp.minorVersion);19. 20. /TheonlyofficialRFBprotocolversionsarecurrently3.3,3.7and3.821. /如果RF
15、B版本号低于3.3不支持。数据处理状态切换为RFB_INVALID抛出异常22. if(cp.beforeVersion(3,3)23. 24. charmsg256;25. sprintf(msg,ServergaveunsupportedRFBprotocolversion%d.%d,26. cp.majorVersion,cp.minorVersion);27. vlog.error(msg);28. state_=RFBSTATE_INVALID;29. throwException(msg);30. 31. elseif(useProtocol3_3|cp.beforeVersion
16、(3,7)32. 33. cp.setVersion(3,3);34. 35. elseif(cp.afterVersion(3,8)36. 37. cp.setVersion(3,8);38. 39. /这里写入版本号信息40. cp.writeVersion(os);41. /Viewer切换数据处理状态RFBSTATE_SECURITY_TYPES42. state_=RFBSTATE_SECURITY_TYPES;43. 44. (UsingRFBprotocolversion%d.%d,45. cp.majorVersion,cp.minorVersion);46.
17、 47. /向服务器发送版本号48. voidConnParams:writeVersion(rdr:OutStream*os)49. 50. charstr13;51. sprintf(str,RFB%03d.%03dn,majorVersion,minorVersion);52. os-writeBytes(str,12);53. os-flush();54. 这个函数发送的内容00000000524642203030332E3030380ARFB003.008.长度为12个字节这时候VNCViewer的数据处理状态为RFBSTATE_SECURITY_TYPES3.vnc收到来自view
18、er的版本信息因为VNC当前的数据处理状态是RFBSTATE_PROTOCOL_VERSION所以会进入processVersionMsg()函数处理viewer发送过来的版本信息cppview plaincopyprint?1. /处理RFBSTATE_PROTOCOL_VERSION2. voidSConnection:processVersionMsg()3. 4. vlog.debug(readingprotocolversion);5. booldone;6. /读取来自viewer的版本号7. if(!cp.readVersion(is,&done)8. 9. state_=RFB
19、STATE_INVALID;10. throwException(readingversionfailed:notanRFBclient?);11. 12. if(!done)13. return;14. 15. (Clientneedsprotocolversion%d.%d,cp.majorVersion,cp.minorVersion);16. 17. if(cp.majorVersion!=3)18. 19. /unknownprotocolversion20. charmsg256;21. sprintf(msg,Error:clientneedsprotocolv
20、ersion%d.%d,serverhas%d.%d,cp.majorVersion,cp.minorVersion,defaultMajorVersion,defaultMinorVersion);22. throwConnFailedException(msg);23. 24. 25. if(cp.minorVersion!=3&cp.minorVersion!=7&cp.minorVersion!=8)26. 27. vlog.error(Clientusesunofficialprotocolversion%d.%d,cp.majorVersion,cp.minorVersion);2
21、8. if(cp.minorVersion=8)29. cp.minorVersion=8;30. elseif(cp.minorVersion=7)31. cp.minorVersion=7;32. else33. cp.minorVersion=3;34. vlog.error(Assumingcompatibilitywithversion%d.%d,cp.majorVersion,cp.minorVersion);35. 36. 37. versionReceived();38. 39. /这里是获取到加密类型40. std:listsecTypes;41. std:list:iter
22、atori;42. securityFactory-getSecTypes(&secTypes,reverseConnection);43. 44. if(cp.isVersion(3,3)45. 46. /copewithlegacy3.3clientonlyifnoauthenticationorvnc47. /authenticationissupported.48. for(i=secTypes.begin();i!=secTypes.end();i+)49. 50. if(*i=secTypeNone|*i=secTypeVncAuth)51. break;52. 53. if(i=
23、secTypes.end()54. 55. charmsg256;56. sprintf(msg,Nosupportedsecuritytypefor%d.%dclient,57. cp.majorVersion,cp.minorVersion);58. throwConnFailedException(msg);59. 60. 61. os-writeU32(*i);62. if(*i=secTypeNone)63. os-flush();64. state_=RFBSTATE_SECURITY;65. security=securityFactory-getSSecurity(*i,rev
24、erseConnection);66. processSecurityMsg();67. return;68. 69. 70. /listsupportedsecuritytypesfor=3.7clients71. if(secTypes.empty()72. throwConnFailedException(Nosupportedsecuritytypes);73. 74. os-writeU8(secTypes.size();75. for(i=secTypes.begin();i!=secTypes.end();i+)76. os-writeU8(*i);77. os-flush();
25、78. state_=RFBSTATE_SECURITY_TYPE;79. 80. 这个函数主要是81. a.验证RFB版本号82. b.获取到加密类型83. c.发送加密类型到VncViewer84. d.设置数据处理标志为RFBSTATE_SECURITY_TYPE4.vncViewer状态为RFBSTATE_SECURITY_TYPES收到vnc发送过来的加密类型后执行processSecurityTypesMsg()cppview plaincopyprint?1. voidCConnection:processSecurityTypesMsg()2. 3. vlog.debug(pr
26、ocessingsecuritytypesmessage);4. 5. intsecType=secTypeInvalid;6. 7. if(cp.isVersion(3,3)8. 9. 10. /legacy3.3servermayonlyoffervncauthenticationornone11. secType=is-readU32();12. if(secType=secTypeInvalid)13. 14. throwConnFailedException();15. 16. elseif(secType=secTypeNone|secType=secTypeVncAuth)17.
27、 18. intj;19. for(j=0;j=3.7serverwillofferusalist35. intnServerSecTypes=is-readU8();36. if(nServerSecTypes=0)37. throwConnFailedException();38. 39. intsecTypePos=nSecTypes;40. for(inti=0;ireadU8();43. vlog.debug(Serverofferssecuritytype%s(%d),44. secTypeName(serverSecType),serverSecType);45. 46. /If
28、wehaventalreadychosenasecType,trythisone47. /Ifweareusingtheclientspreferencefortypes,48. /wekeeptryingtypes,tofindtheonethatmatchesand49. /whichappearsfirstintheclientslistofsupportedtypes.50. if(secType=secTypeInvalid|clientSecTypeOrder)51. 52. for(intj=0;jnSecTypes;j+)53. 54. if(secTypesj=serverS
29、ecType&jwriteU8(secType);69. os-flush();70. vlog.debug(Choosingsecuritytype%s(%d),secTypeName(secType),secType);71. 72. 73. 74. if(secType=secTypeInvalid)75. 76. state_=RFBSTATE_INVALID;77. vlog.error(Nomatchingsecuritytypes);78. throwException(Nomatchingsecuritytypes);79. 80. 81. state_=RFBSTATE_SE
30、CURITY;82. /因为这里没有开启认证,所以security返回的是一个CSecurityNone类83. security=getCSecurity(secType);84. /调用getCSecurity函数进行下一步的认证工作85. processSecurityMsg();86. 87. 88. CSecurity*CConn:getCSecurity(intsecType)89. 90. switch(secType)91. 92. casesecTypeNone:93. returnnewCSecurityNone();94. casesecTypeVncAuth:95. r
31、eturnnewCSecurityVncAuth(this);96. default:97. throwException(UnsupportedsecType?);98. 99. 这个函数a.获取加密类型b.切换数据处理状态为RFBSTATE_SECURITYC.生成用例处理加密的类d.调用processSecurityMsg()函数继续处理加密cppview plaincopyprint?1. voidCConnection:processSecurityMsg()2. 3. vlog.debug(processingsecuritymessage);4. if(security-proc
32、essMsg(this)5. 6. state_=RFBSTATE_SECURITY_RESULT;7. processSecurityResultMsg();8. 9. 因为我这里没有开启认证,所以processMsg()函数直接返回TRUE就通过验证。如果开启了VNC验证,会执行这个函数cppview plaincopyprint?1. boolCSecurityVncAuth:processMsg(CConnection*cc)2. 3. rdr:InStream*is=cc-getInStream();4. rdr:OutStream*os=cc-getOutStream();5. 6
33、. /Readthechallenge&obtaintheuserspassword7. rdr:U8challengevncAuthChallengeSize;8. is-readBytes(challenge,vncAuthChallengeSize);9. PlainPasswdpasswd;10. upg-getUserPasswd(0,&passwd.buf);11. 12. /Calculatethecorrectresponse13. rdr:U8key8;14. intpwdLen=strlen(passwd.buf);15. for(inti=0;i8;i+)16. keyi
34、=ipwdLen?passwd.bufi:0;17. deskey(key,EN0);18. for(intj=0;jwriteBytes(challenge,vncAuthChallengeSize);23. os-flush();24. returntrue;25. 认证通过后数据处理状态切换为RFBSTATE_SECURITY_RESULT继续执行processSecurityResultMsg()函数cppview plaincopyprint?1. voidCConnection:processSecurityResultMsg()2. 3. vlog.debug(processin
35、gsecurityresultmessage);4. intresult;5. if(cp.beforeVersion(3,8)&security-getType()=secTypeNone)6. 7. result=secResultOK;8. 9. else10. 11. if(!is-checkNoWait(1)12. return;13. result=is-readU32();14. 15. switch(result)16. 17. casesecResultOK:18. securityCompleted();19. return;20. casesecResultFailed:
36、21. vlog.debug(authfailed);22. break;23. casesecResultTooMany:24. vlog.debug(authfailed-toomanytries);25. break;26. default:27. throwException(Unknownsecurityresultfromserver);28. 29. CharArrayreason;30. if(cp.beforeVersion(3,8)31. reason.buf=strDup(Authenticationfailure);32. else33. reason.buf=is-r
37、eadString();34. state_=RFBSTATE_INVALID;35. throwAuthFailureException(reason.buf);36. 验证通过执行securityCompleted()函数cppview plaincopyprint?1. voidCConnection:securityCompleted()2. 3. state_=RFBSTATE_INITIALISATION;4. reader_=newCMsgReaderV3(this,is);5. writer_=newCMsgWriterV3(&cp,os);6. vlog.debug(Auth
38、enticationsuccess!);7. authSuccess();8. writer_-writeClientInit(shared);9. 设置vncViewer的数据处理状态为RFBSTATE_INITIALISATION创建CMsgReaderV3类用于读取创建CMsgWriterV3类用于写入调用writeClientInit函数cppview plaincopyprint?1. voidCMsgWriterV3:writeClientInit(boolshared)2. 3. /是否分享屏幕默认为false4. os-writeU8(shared);5. endMsg();6
39、. 7. voidCMsgWriterV3:endMsg()8. 9. os-flush();10. 这里,viewer数据处理状态为RFBSTATE_INITIALISATION所以这个函数发送了两次数据第一次是发送加密类型 os-writeU8(secType)第二次是发送的屏幕是否共享 os-writeU8(shared);发送数据内容5.vnc当前状态为RFBSTATE_SECURITY_TYPE调用processSecurityTypeMsg函数来处理Viewer的数据cppview plaincopyprint?1. /RFBSTATE_SECURITY_TYPE2. voidSC
40、onnection:processSecurityTypeMsg()3. 4. vlog.debug(processingsecuritytypemessage);5. /第一次是读取加密类型6. intsecType=is-readU8();7. 8. /Verifythattherequestedsecuritytypeshouldbeoffered9. std:listsecTypes;10. std:list:iteratori;11. securityFactory-getSecTypes(&secTypes,reverseConnection);12. for(i=secTypes.begin();i!=secTypes.end();i+)13. if(*i=secType)14. break;15. if(i=secTypes.end()16. throwException(Requestedsecuritytypenotavailable);17. 18. (Clientrequestssecuritytype%s(%d),secTypeName(secType),secType);19. 20. try21. 22. state
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 评析我国采购法制度
- 临时采购使用管理制度
- 采购考察制度
- 基本药物采购及相关制度
- 企业申请物品采购制度
- 材料采购政策法规制度
- 苏州个人计算机采购制度
- 业委会采购制度及流程
- 自行采购如何管理制度
- 钢结构工程材料采购制度
- 低碳-零碳产业园运行管理规范DB15-T 3993-2025
- DB35∕T 84-2020 造林技术规程
- 《基于FCFF模型的三一重工企业价值评估的案例分析报告》16000字【论文】
- 第5课 隋唐时期的民族交往与交融 教案2024-2025学年七年级历史下册新课标
- 2025年春新湘教版数学七年级下册课件 1.1.4 单项式的乘法 1.1.5 多项式的乘法
- 2025年驾照C1证考试科目一必考题库750题及答案
- 云南省相对集中行政处罚权事项指导目录(2024年版)
- 考点24 人与环境-五年(2020-2024年)高考生物学真题专项分类汇编
- 概率论与数理统计章节练习题及答案
- 外伤性白内障护理查房
- 医疗设备的保养与维护
评论
0/150
提交评论