开源远程控制RealVNC源代码中的通讯协议RFB
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
开源远程控制RealVNC源代码中的通讯协议RFB(远程帧缓冲)----- 一
分类:远程控制业余研究开源软件2014-05-27 18:04 2040人阅读评论(1) 收藏举报在网上流传的gh0st3.6源代码中,远程桌面总是存在CPU占用率高和画面更新不及时等
问题。
于是想到了著名的开源远程控制RealVNC 它采用了远程帧缓存的协议(Remote Frame buffer)
在网上找到的一段关于RFB的描述
RFB 是真正意义上的“瘦客机”协议。
RFB协议设计的重点在于减少对客户端的硬件需求。
这样
客户端就可以运行在许多不同的硬件上,客户机的任务实现上就会尽量的简单。
RFB协议对于客户端是无状态的。
也就是说:如果客户端从服务器端断开,那么如果它重新连
接相同的服务器,客户端的状态会被保存。
甚至,一个不同的客户端可以用来连接相同的RFB
服务器。
而在新的客户端已经能够获得与前一个客户端相同的用户状态。
因此,用户的应用接
口变的非常便捷。
只要合适的网络连接存在,那么用户就可以使用自己的应用程序,并且这些应用会一直保存,
即使在不同的接入点也不会变化。
这样无论在哪,系统都会给用户提供一个熟悉、独特的计算
环境。
显示协议
显示协议是建立在“把像素数据放在一个由x,y定位的方框内”这单一图形基础之上的。
乍一看上去,把这么多的用户接口组件绘制出来是非常低效的方法。
但是,允许不同的像素数
据编码方式,使得我们在处理不同的参数(如:网络带宽,客户端的绘制速度,服务器处理速度)有了很大程度的灵活性。
通过矩形的序列来完成帧缓存的更新。
一次更新代表着从一个可用帧缓存状态转换到另一个可用,因此有点和视频的桢类似。
尽管矩形的更新一般是分开的,但是并不是必须的。
显示协议的更新部分是由客户端通过命令驱动的。
也就是说,更新只是在服务器端响应客户端
的请求时发生的。
这样就让协议更新质量是可变的。
客户端/网络越慢,更新速度也就越慢。
对于一些应用来说,相同区域的更新是连续不断的。
如果用一个慢的客户端,那么帧缓存的缓
存状态是可以被忽略的。
这样也可以减少对客户端网络速度和绘制速度的要求。
输入协议
输入协议是基于标准工作站的键盘和鼠标等设备的连接协议。
输入事件就是通过把客户端的输入发送到服务器端。
这些输入事件也可以通过非标准的I /O 设备来综合。
例如,手写笔引擎可能产生一个键盘事件。
像素数据的表示
初始的交互涉及到RFB客户端和服务器之间传输像素数据格式和编码方式的协调。
这种协调
被设计的让客户端的工作尽量简单。
而设计的底线是:服务器必须按照客户端的要求格式来提供像素数据。
如果客户端可以同样的处理多种数据格式或编码格式,那么一般会选择服务器端易于生成的格式。
像素格式涉及如何通过像素值来实现不同颜色的重现。
最常用的一般像素格式是24 位或16
位的“真彩色”,它通过位来直接实现像素值到红、绿、蓝亮度的转换。
8 位“颜色映射”可以任
意映射像素值到RGB亮度的转换。
编码指一个矩形的像素数据如何通过网线传输。
每个像素数据的矩形都加上了一个头,给定矩形在屏幕上的X、Y坐标、矩形的宽和高,以及指定的编码类型。
而后数据本身就是采用这种
特定的编码方式。
数据本身遵循特定的编码。
目前的编码方式主要有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顺序。
big endian或者little endian跟cpu有关,从而影响整数在内存中的排列顺序。
big endian是高字节在前,little endian是低字节在前,网络字节序一般是big-endian。
PIXEL代表一个像素值bytesPerPixel字节,8XbytesPerPixel = bits-per-pixel
RealVNC 分为客户端和服务端
客户端名为 VNCViewer
服务端名为 VNC
客户端连接到服务器端
这时候服务端会给客户端发送当前提供最大支持的版本号。
[cpp]view plaincopyprint?
1.//初始化RFB协议
2.void SConnection::initialiseProtocol()
3.{
4. cp.writeVersion(os);
5. state_ = RFBSTATE_PROTOCOL_VERSION;
6.}
7.//写入版本
8.void ConnParams::writeVersion(rdr::OutStream* os)
9.{
10.char str[13];
11. sprintf(str, "RFB %03d.%03d\n", majorVersion
, minorVersion);
12. os->writeBytes(str, 12);
13. os->flush();
14.}
这里对应的发送的内容如下
00000000 52 46 42 20 30 30 33 2E 30 30 38 0A RFB 003.008.
发送数据长度12
发送数据内容RFB 003.008
此时VNC 的数据处理状态为RFBSTATE_PROTOCOL_VERSION
2.viewer收到来自vnc的版本号信息
因为viewer在init()函数中已经设置数据处理状态为RFBSTATE_PROTOCOL_VERSION [cpp]view plaincopyprint?
1.void CConnection::initialiseProtocol()
2.{
3. state_ = RFBSTATE_PROTOCOL_VERSION;
4.}
[cpp]view plaincopyprint?
1.void CConnection::processMsg()
2.{
3.switch (state_)
4. {
5.case RFBSTATE_PROTOCOL_VERSION:
6. processVersionMsg();
7.break;
8.case RFBSTATE_SECURITY_TYPES:
9. processSecurityTypesMsg();
10.break;
11.case RFBSTATE_SECURITY:
12. processSecurityMsg();
13.break;
14.case RFBSTATE_SECURITY_RESULT:
15. processSecurityResultMsg();
16.break;
17.case RFBSTATE_INITIALISATION:
18. processInitMsg();
19.break;
20.case RFBSTATE_NORMAL:
21. reader_->readMsg();
22.break;
23.case RFBSTATE_UNINITIALISED:
24.throw Exception("CConnection::processMsg
: not initialised yet?");
25.default:
26.throw Exception("CConnection::processMsg
: invalid state");
27. }
28.}
[cpp]view plaincopyprint?
1.进入 processVersionMsg()函数
2.//处理 RFBSTATE_PROTOCOL_VERSION
3.void CConnection::processVersionMsg()
4.{
5. vlog.debug("reading protocol version");
6.bool done;
7.//这里读取服务器版本,如果读取失败数据处理状态切换
为 RFBSTATE_INVALID
8.if (!cp.readVersion(is, &done))
9. {
10. state_ = RFBSTATE_INVALID;
11.throw Exception("reading version failed:
not an RFB server?");
12. }
13.//读取失败返回
14.if (!done)
15.return;
16.
17. ("Server supports RFB protocol vers
ion %d.%d",
18. cp.majorVersion, cp.minorVersion);
19.
20.// The only official RFB protocol versions a
re currently 3.3, 3.7 and 3.8
21.//如果RFB版本号低于 3.3 不支持。
数据处理状态切
换为 RFB_INVALID 抛出异常
22.if (cp.beforeVersion(3, 3))
23. {
24.char msg[256];
25. sprintf(msg, "Server gave unsupported RF
B protocol version %d.%d",
26. cp.majorVersion, cp.minorVersion);
27. vlog.error(msg);
28. state_ = RFBSTATE_INVALID;
29.throw Exception(msg);
30. }
31.else if (useProtocol3_3 || cp.beforeVersion(
3, 7))
32. {
33. cp.setVersion(3, 3);
34. }
35.else if (cp.afterVersion(3, 8))
36. {
37. cp.setVersion(3, 8);
38. }
39.//这里写入版本号信息
40. cp.writeVersion(os);
41.//Viewer切换数据处理状
态 RFBSTATE_SECURITY_TYPES
42. state_ = RFBSTATE_SECURITY_TYPES;
43.
44. ("Using RFB protocol version %d.%d"
,
45. cp.majorVersion, cp.minorVersion);
46.}
47.//向服务器发送版本号
48.void ConnParams::writeVersion(rdr::OutStream* os
)
49.{
50.char str[13];
51. sprintf(str, "RFB %03d.%03d\n", majorVersion
, minorVersion);
52. os->writeBytes(str, 12);
53. os->flush();
54.}
这个函数发送的内容
00000000 52 46 42 20 30 30 33 2E 30 30 38 0A RFB 003.008.
长度为12 个字节
这时候VNCViewer的数据处理状态为RFBSTATE_SECURITY_TYPES
3.vnc收到来自viewer的版本信息
因为VNC当前的数据处理状态是RFBSTATE_PROTOCOL_VERSION
所以会进入processVersionMsg()函数处理viewer发送过来的版本信息
[cpp]view plaincopyprint?
1.//处理 RFBSTATE_PROTOCOL_VERSION
2.void SConnection::processVersionMsg()
3.{
4. vlog.debug("reading protocol version");
5.bool done;
6.//读取来自viewer的版本号
7.if (!cp.readVersion(is, &done))
8. {
9. state_ = RFBSTATE_INVALID;
10.throw Exception("reading version failed:
not an RFB client?");
11. }
12.if (!done)
13.return;
14.
15. ("Client needs protocol version %d.
%d",cp.majorVersion, cp.minorVersion);
16.
17.if (cp.majorVersion != 3)
18. {
19.// unknown protocol version
20.char msg[256];
21. sprintf(msg, "Error: client needs protoc
ol version %d.%d, server has %d.%d",cp.majorVersion, cp.minorVersion,defaultMajorVersion, defaultMinorVers ion);
22. throwConnFailedException(msg);
23. }
24.
25.if (cp.minorVersion != 3 && cp.minorVersion
!= 7 && cp.minorVersion != 8)
26. {
27. vlog.error("Client uses unofficial proto
col version %d.%d",cp.majorVersion, cp.minorVersion);
28.if (cp.minorVersion >= 8)
29. cp.minorVersion = 8;
30.else if (cp.minorVersion == 7)
31. cp.minorVersion = 7;
32.else
33. cp.minorVersion = 3;
34. vlog.error("Assuming compatibility with
version %d.%d",cp.majorVersion, cp.minorVersion);
35. }
36.
37. versionReceived();
38.
39.//这里是获取到加密类型
40. std::list<rdr::U8> secTypes;
41. std::list<rdr::U8>::iterator i;
42. securityFactory-
>getSecTypes(&secTypes, reverseConnection);
43.
44.if (cp.isVersion(3, 3))
45. {
46.// cope with legacy 3.3 client only if "
no authentication" or "vnc
47.// authentication" is supported.
48.for (i = secTypes.begin(); i != secTypes
.end(); i++)
49. {
50.if (*i == secTypeNone || *i == secTy
peVncAuth)
51.break;
52. }
53.if (i == secTypes.end())
54. {
55.char msg[256];
56. sprintf(msg, "No supported security
type for %d.%d client",
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, reverseConnection);
66. processSecurityMsg();
67.return;
68. }
69.
70.// list supported security types for >=3.7 c
lients
71.if (secTypes.empty())
72. throwConnFailedException("No supported s
ecurity types");
73.
74. os->writeU8(secTypes.size());
75.for (i = secTypes.begin(); i != secTypes.end
(); i++)
76. os->writeU8(*i);
77. os->flush();
78. state_ = RFBSTATE_SECURITY_TYPE;
79.}
80.这个函数主要是
81. a.验证RFB版本号
82. b.获取到加密类型
83. c.发送加密类型到VncViewer
84. d.设置数据处理标志为 RFBSTATE_SECURITY_TYPE
4.vncViewer状态为RFBSTATE_SECURITY_TYPES
收到vnc发送过来的加密类型后执行
processSecurityTypesMsg()
[cpp]view plaincopyprint?
1.void CConnection::processSecurityTypesMsg()
2.{
3. vlog.debug("processing security types message");
4.
5.int secType = secTypeInvalid;
6.
7.if (cp.isVersion(3, 3))
8. {
9.
10.// legacy 3.3 server may only offer "vnc
authentication" or "none"
11. secType = is->readU32();
12.if (secType == secTypeInvalid)
13. {
14. throwConnFailedException();
15. }
16.else if (secType == secTypeNone || secTy
pe == secTypeVncAuth)
17. {
18.int j;
19.for (j = 0; j < nSecTypes; j++)
20.if (secTypes[j] == secType)
21.break;
22.if (j == nSecTypes)
23. secType = secTypeInvalid;
24. }
25.else
26. {
27. vlog.error("Unknown 3.3 security typ
e %d", secType);
28.throw Exception("Unknown 3.3 securit
y type");
29. }
30.
31. }
32.else
33. {
34.// >=3.7 server will offer us a list
35.int nServerSecTypes = is->readU8();
36.if (nServerSecTypes == 0)
37. throwConnFailedException();
38.
39.int secTypePos = nSecTypes;
40.for (int i = 0; i < nServerSecTypes; i++
)
41. {
42. rdr::U8 serverSecType = is-
>readU8();
43. vlog.debug("Server offers security t
ype %s(%d)",
44. secTypeName(serverSecType), serv
erSecType);
45.
46.// If we haven't already chosen a se
cType, try this one
47.// If we are using the client's pref
erence for types,
48.// we keep trying types, to find the
one that matches and
49.// which appears first in the client
's list of supported types.
50.if (secType == secTypeInvalid || cli
entSecTypeOrder)
51. {
52.for (int j = 0; j < nSecTypes; j
++)
53. {
54.if (secTypes[j] == serverSec
Type && j < secTypePos)
55. {
56. secType = secTypes[j];
57. secTypePos = j;
58.break;
59. }
60. }
61.// NB: Continue reading the rema
ining server secTypes, but ignore them
62. }
63. }
64.
65.// Inform the server of our decision
66.if (secType != secTypeInvalid)
67. {
68. os->writeU8(secType);
69. os->flush();
70. vlog.debug("Choosing security type %
s(%d)", secTypeName(secType), secType);
71. }
72. }
73.
74.if (secType == secTypeInvalid)
75. {
76. state_ = RFBSTATE_INVALID;
77. vlog.error("No matching security types")
;
78.throw Exception("No matching security ty
pes");
79. }
80.
81. state_ = RFBSTATE_SECURITY;
82.//因为这里没有开启认证,所以security返回的是一
个CSecurityNone类
83. security = getCSecurity(secType);
84.//调用getCSecurity函数进行下一步的认证工作
85. processSecurityMsg();
86.}
87.
88.CSecurity* CConn::getCSecurity(int secType)
89.{
90.switch (secType)
91. {
92.case secTypeNone:
93.return new CSecurityNone();
94.case secTypeVncAuth:
95.return new CSecurityVncAuth(this);
96.default:
97.throw Exception("Unsupported secType?");
98. }
99.}
这个函数
a.获取加密类型
b.切换数据处理状态为RFBSTATE_SECURITY
C.生成用例处理加密的类
d.调用processSecurityMsg()函数继续处理加密
[cpp]view plaincopyprint?
1.void CConnection::processSecurityMsg()
2.{
3. vlog.debug("processing security message");
4.if (security->processMsg(this))
5. {
6. state_ = RFBSTATE_SECURITY_RESULT;
7. processSecurityResultMsg();
8. }
9.}
因为我这里没有开启认证,所以processMsg()函数直接返回TRUE就通过验证。
如果开启了VNC验证,会执行这个函数
[cpp]view plaincopyprint?
1.bool CSecurityVncAuth::processMsg(CConnection* cc)
2.{
3. rdr::InStream* is = cc->getInStream();
4. rdr::OutStream* os = cc->getOutStream();
5.
6.// Read the challenge & obtain the user's passwor
d
7. rdr::U8 challenge[vncAuthChallengeSize];
8. is->readBytes(challenge, vncAuthChallengeSize);
9. PlainPasswd passwd;
10. upg->getUserPasswd(0, &passwd.buf);
11.
12.// Calculate the correct response
13. rdr::U8 key[8];
14.int pwdLen = strlen(passwd.buf);
15.for (int i = 0; i < 8; i++)
16. key[i] = i < pwdLen ? passwd.buf[i] : 0;
17. deskey(key, EN0);
18.for (int j = 0; j < vncAuthChallengeSize; j
+= 8)
19. des(challenge + j, challenge + j);
20.
21.// Return the response to the server
22. os-
>writeBytes(challenge, vncAuthChallengeSize);
23. os->flush();
24.return true;
25.}
认证通过后数据处理状态切换为
RFBSTATE_SECURITY_RESULT
继续执行processSecurityResultMsg()函数
[cpp]view plaincopyprint?
1.void CConnection::processSecurityResultMsg()
2.{
3. vlog.debug("processing security result message");
4.int result;
5.if (cp.beforeVersion(3, 8) && security-
>getType() == secTypeNone)
6. {
7. result = secResultOK;
8. }
9.else
10. {
11.if (!is->checkNoWait(1))
12.return;
13. result = is->readU32();
14. }
15.switch (result)
16. {
17.case secResultOK:
18. securityCompleted();
19.return;
20.case secResultFailed:
21. vlog.debug("auth failed");
22.break;
23.case secResultTooMany:
24. vlog.debug("auth failed -
too many tries");
25.break;
26.default:
27.throw Exception("Unknown security result
from server");
28. }
29. CharArray reason;
30.if (cp.beforeVersion(3, 8))
31. reason.buf = strDup("Authentication fail
ure");
32.else
33. reason.buf = is->readString();
34. state_ = RFBSTATE_INVALID;
35.throw AuthFailureException(reason.buf);
36.}
验证通过
执行securityCompleted()函数
[cpp]view plaincopyprint?
1.void CConnection::securityCompleted()
2.{
3. state_ = RFBSTATE_INITIALISATION;
4. reader_ = new CMsgReaderV3(this, is);
5. writer_ = new CMsgWriterV3(&cp, os);
6. vlog.debug("Authentication success!");
7. authSuccess();
8. writer_->writeClientInit(shared);
9.}
设置vncViewer的数据处理状态为RFBSTATE_INITIALISATION
创建CMsgReaderV3类用于读取
创建CMsgWriterV3类用于写入
调用writeClientInit 函数
[cpp]view plaincopyprint?
1.void CMsgWriterV3::writeClientInit(bool shared)
2.{
3.//是否分享屏幕默认为false
4. os->writeU8(shared);
5. endMsg();
6.}
7.void CMsgWriterV3::endMsg()
8.{
9. os->flush();
10.}
这里,viewer数据处理状态为RFBSTATE_INITIALISATION
所以这个函数发送了两次数据
第一次是发送加密类型 os->writeU8(secType)
第二次是发送的屏幕是否共享 os->writeU8(shared);
发送数据内容
5. vnc当前状态为RFBSTATE_SECURITY_TYPE
调用processSecurityTypeMsg函数来处理Viewer的数据
[cpp]view plaincopyprint?
1.//RFBSTATE_SECURITY_TYPE
2.void SConnection::processSecurityTypeMsg()
3.{
4. vlog.debug("processing security type message");
5.//第一次是读取加密类型
6.int secType = is->readU8();
7.
8.// Verify that the requested security type should
be offered
9. std::list<rdr::U8> secTypes;
10. std::list<rdr::U8>::iterator i;
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.throw Exception("Requested security
type not available");
17.
18. ("Client requests security type %s(
%d)",secTypeName(secType), secType);
19.
20.try
21. {
22. state_ = RFBSTATE_SECURITY;
23.//同viewer一样,这里根据加密类型生成对应的加密
处理类如果有加密就是 CSecurityVncAuth 类这里因为没有启动加密,所以生成的是SSecurityNone类
24. security = securityFactory-
>getSSecurity(secType, reverseConnection);
25. }
26.catch (rdr::Exception& e)
27. {
28. throwConnFailedException(e.str());
29. }
30.
31. processSecurityMsg();
32.}
processSecurityMsg()继续处理数据
[cpp]view plaincopyprint?
1.void SConnection::processSecurityMsg()
2.{
3. vlog.debug("processing security message");
4.try
5. {
6.//对于未加密的认证类处理processMsg函数,总是返回
true
7.bool done = security->processMsg(this);
8.if (done)
9. {
10. state_ = RFBSTATE_QUERYING;
11. queryConnection(security-
>getUserName());
12. }
13. }
14.catch (AuthFailureException& e)
15. {
16. vlog.error("AuthFailureException: %s", e
.str());
17. os->writeU32(secResultFailed);
18.if (!cp.beforeVersion(3, 8)) // 3.8 onwa
rds have failure message
19. os->writeString(e.str());
20. os->flush();
21.throw;
22. }
23.}
这个函数切换vnc数据处理状态为RFBSTATE_QUERYING
执行queryConnection函数
[cpp]view plaincopyprint?
1.void SConnection::queryConnection(const char* userNam
e)
2.{
3. approveConnection(true);
4.}
这个函数会进入approveConnection()函数,传入参数为true 即是接受连接
[cpp]view plaincopyprint?
1.void SConnection::approveConnection(bool accept, cons
t char* reason)
2.{
3.if (state_ != RFBSTATE_QUERYING)
4.throw Exception("SConnection::approveConnecti
on: invalid state");
5.
6.if (!reason)
7. reason = "Authentication failure";
8.
9.if (!cp.beforeVersion(3, 8) || security-
>getType() != secTypeNone)
10. {
11.if (accept)
12. {
13. os->writeU32(secResultOK);
14. }
15.else
16. {
17. os->writeU32(secResultFailed);
18.if (!cp.beforeVersion(3, 8)) // 3.8
onwards have failure message
19. os->writeString(reason);
20. }
21. os->flush();
22. }
23.
24.if (accept)
25. {
26. state_ = RFBSTATE_INITIALISATION;
27. reader_ = new SMsgReaderV3(this, is);
28. writer_ = new SMsgWriterV3(&cp, os);
29. authSuccess();
30. }
31.else
32. {
33. state_ = RFBSTATE_INVALID;
34.throw AuthFailureException(reason);
35. }
36.}
如果RFB版本不低于3.8这个函数写入secResultOK 也就是0
否则写入错误信息
切换数据处理状态为RFBSTATE_INITIALISATION
然后调用一个空函数
[cpp]view plaincopyprint?
1.void SConnection::authSuccess()
2.{
3.
4.}
所以在这一次处理中先读取了加密类型。
但是对于发送过来的屏幕是否共享这个值是否有读取,我还没有找到相关的代码。
接着发送secResultOK 的值0
Vnc状态RFBSTATE_INITIALISATION。