转自
http://blog.csdn.net/Blue_Dream_/archive/2007/08/25/1758541.aspx下面的内容是用 VC.NET 的调试器调试的整个源码而确定的执行流程. 在分析代码时尽量不要静态的分析代码,这样速度很慢的。利用调试器我们可以通过简单的设置断点来跟踪整个执行流程。
WINVNC 调试其整体流程
在 WinMain 中进行
(1) 初始化套接字库 VSocketSystem
(2) 解析命令行参数
(3) 调用主窗口过程 WinVNCAppMain
WinVNCAppMain 中进行
(1) 确认当前只有一个本实例运行,vncInstHandler
(2) 创建 Server 类, 该类的作用:
动态添加和删除客户端
把本地窗口的更新发送给所有连接的客户端
把客户端的鼠标和键盘事件传递给本地
创建套套接字的连接
(3) 创建菜单和托盘图标 vncMenu
vncMenu中进行:
(1) 构造函数中进行:创建托盘图标窗口
把窗口托盘图标句柄加入到 vncServer.m_notifyList 中
初始化 vncProperties->Init
在调用 Init 中 vncProperties->Load 调用 vncProperties ->ApplyUserPrefs 调用 server->SockConnect 完成各种线程的创建和端口邦定工作。
在 Init 中得到密码检查是否需要验证。
当我们双击图标时vncProperties->ApplyUserPrefs会被调用,
vncProperties->ApplyUserPrefs 调用 vncServer::SockConnect 完成可能的程序重新启动。
当有客户端连接时:
当有客户端连接时,run_undetached 线程接收到连接后调用 AddClient 把客户端添加到一个客户端的映射数组中 Key 是 ClientSocket,值是新建的客户端的类。
然后创建客户端线程.
把客户端添加到未授权客户端列表.
客户端线程的工作(处理与客户端相关的工作):
客户端线程类vncClientThread的Run函数,就相当于线程函数(在线程中被调用)。
在vncClientThread->run 函数中调用 vncClientThread::InitVersion() 函数, InitVersion 函数中工作如下:
(1) 首先向客户端发送自己的(服务器方的)版本号
(2) 接收客户端的版本号
(3) 验证版本号
客户端线程类vncClientThread的Run函数调用vncClientThread->InitAuthenticate
InitAuthenticate的工作是:
(1) 给客户端发送认证请求
(2) 验证客户端是否合法
vncDesktopThread->run_undetached 线程的工作(最核心的功能):
(1) 该线程调用vncDesktop::Startup():
进行所有的初始化工作:
1. 设置象素格式和位图信息
2. 设置各种系统 Hook, 添加系统挂钩,包括屏幕, 键盘,鼠标。
3. 设置一个定时器来处理拉模式(polling mode),每一秒钟执行一次.
这样 TriggerUpdate 例程每秒钟被执行一次.
(2) 设置处理剪切板消息
(3) 创建一个缓存区域对象。所有的区域更新消息都被缓存在该对象中,仅当 TriggerUpdate被触发时,才把这些消息传给所有的客户端。
认证流程:
1. 版本认证过程:
去掉该版本认证过程。
该版本认证过程:大致是服务器端
WinVNC 客户端分析
WinMainàVNCviewerApp32::NewConnection(创建ClientConnection 对象)à ClientConnection::Run
ClientConnection::Run 的功能:
(1) 弹出窗口,接收用户输入的服务器的IP地址和端口号
(2) 取得连接信息,进行连接 ClientConnection::GetConnectDetails()
(3) 版本信息的认证 ClientConnection::NegotiateProtocolVersion()
(4) 进行权限的验证 ClientConnection::Authenticate();
修改时间:2007年8月25日星期六
修改内容:去掉了 AuthDialog.cpp,AuthDialog.h ,这个认证会话框的内容是客户端输入服务器的密码才能对服务器端进行远程控制。
修改时间:8/25/2007 9:43:10 AM
修改内容:去掉 log.cpp 和log.h 内容
这个是对各个操作结果内容的记录
对于客户端的代码
该功能实现的一个重要方法:
ClientConnection 类的创建主显示窗口,窗口过程是静态方法
Static ClientConnection::WinProc
ClientConnection 类的创建一个线程,
在线程中调用了 ClientConnection ::run_undetached 这就相当于该类中的方法是线程方法一样。
ClientConnection::run_undetached 分析:
run_undetached 是假的线程方法()中
实现方法可能是:该方法是虚函数,在基类中就已经把该方法作为线程的参数传给了start 函数,该参数是作为函数指针传递的,这样在Start函数中利用函数指针调用该函数就可以了。
继承类只需把run_undetached当做线程方法实现就行了。(这样做的原因是:在线程中不允许线程方法作为其成员,编译不过,是调用约定的问题)
该例程的实现过程:
接收服务器端发送过来的消息类型: frame 更新,ReadBell 等。然后 switch 进入对应的分。
对于 FrameUpdate 的后续处理是:
1. 读取服务器端更新的Rect数目 RectCount,然后进入for循环,次数RectCount
2. 读取每个Rect的头部信息,确定这个Rect的坐标和宽度和高度,以及编码信息
3. 根据编码信息进入swtich 的特定分支, 接收真正的数据
4. 把接收到的 Rect 区域坐标转换成 Windows 坐标。