您的位置:首页 > 其它

远程桌面控制VC源码剖析

2012-08-08 11:21 274 查看

一、引语

这是个VC6.0的远程桌面控制软件,主要功能是桌面控制、支持多种压缩方式、可调整网格空间数目以及色彩模式选择。源码我也不知道从何而来了,今天整理硬盘无疑间发现的。软件中作者没有留名,很老的一个软件,各种办法也没找到出处,那么就当这个软件是一个开源软件吧。

二、结构分析

拿到代码,先看服务器端,RemoteControlServer 文件。

目录结构:(cmd> tree /f |more生成,略有修改)

E:.RemoteControlServer

│ afiedt.buf

│ .........................

│ ServerWindow.001

│ ServerWindow.dsp

│ ServerWindow.dsw

│ ServerWindow.mak

│ ServerWindow.ncb

│ ServerWindow.opt

│ ServerWindow.plg

│ ........................

└─WndProc.h

目录中有*.dsp、*.dsw文件 ,明显可以看出是vc项目。那么有可能是MFC或者win32/win32 console。

用VS2008打开RemoteControlServer项目,查看类视图,class CMainWnd;只有这一个用户的非继承类,看来不可能是MFC了,倒是很像Win32。

接下来就要先找到WinMain或者main函数了,因为文件没几个,凭着直觉和命名规范,果断在WndProc.cpp找到了WinMain。

因为Win32窗口使用的是消息循环机制,那么直接从WinMain开始看代码了。在WinMain中将回调WndProc函数,OnCreate、OnDestroy、OnKeyDown、OnCommand回根据窗口的消息调用,这样就不难理解程序的结构。

整体的结构可以看图,只是为了整体结构的体现,很多地方进行了省略。图一如既往的烂(第二次使用visio我会说么?)





三、网络编程部分

MainWnd.cpp (63L) CMainWnd::OnCreate 中,进行Winsock初始化。

CMainWnd::OnCommand (160L)中,创建LoadWinsock线程进行通信。

Server.c (72L) SelectProtocols函数把一些协议相关的信息放入了pBuf缓冲中,但是pBuf是怎么和套接字关联起来的呢?从头到尾没用过。而且我把SelectProtocols函数调用的那一句注释之后编译,一样能成功链接通信。那这里调用SelectProtocols是怎么起到作用的呢?

Server.c (991L) SelectProtocols函数主要主用是:

1、让所有报文都能到达目的

2、让所有报文都有序到达

3、不使用数据报套接字通信

SelectProtocols函数中有调用memblast,memblast是用内嵌汇编实现的内存拷贝函数,可能是为了某些平台移植、或者程序编译时不使用平台提供的基本运行时。(感谢BinSys解疑)

为了减小CPU的利用率,禁止在socket上将数据发送到缓冲。设置SO_SNDBUF为0,从而使winsock直接发送数据到客户端,而不是将数据缓冲才发送。(msdn:setsockopt

nZero = 0;
setsockopt(Listen, SOL_SOCKET, SO_SNDBUF, (char *)&nZero, sizeof(nZero));


Server.c (105L) 等待用户连接是一个循环等待并阻塞的过程,并且一直等待用户来连接。

一旦有用户连接到服务器,就会进入新的线程ClientThread;

在ClientThread又用了select模型,只有一个用户,也没有设置超时时间,并且select也不比普通的直接recv阻塞等待快啊。这个真的很难理解。难道是为了程序的拓展性(为多用户或者超时之后做一点别的事么?)

从应用层来分析 协议 ,这个程序使用的是各种“命令”。

1.REFRESH

2.WM_系列

3.RESOLUTION

4.DISCONNECT

WM_是一个系列,又分成三个字系列.

1.鼠标消息

2.键盘消息

3.通用消息:
色彩模式,网格数和压缩消息

四、屏幕采集部分

这部分主要是就服务器采集屏幕,然后发送给客户端。

定时采集屏幕发送给用户?不,这样流量的不能接受,而且是没必要的。

采用每次屏幕改变的时候才返回新的屏幕呢?看样子不错,但是还可以优化。

把屏幕划通过网格分成很多小块,每次只发送改变的那些块,这样还不错吧?

这个程序就是这样设计的,并且也是这个程序设计最巧妙的地方。如果做到最好就是,直接获得变化的那些区域,发送变化的那个区域过去,这个区域很有可能是不规则的。用网格的办法来说,就是网格的每个区域分辨率只有1*1,但是不可能这样做了,要保留所有变化的像素点,不停的遍历对比每一个像素,这样无疑增加是CPU的负担。获得屏幕变化的部分是通过对比位图的出来的(Server.c (683L))。

MainWnd.cpp (166L) 调用InitDisplay初始化。屏幕刷新是用户提出的请求,当服务器收到刷新屏幕的请求之后,首先获取需要刷新的网格区域,对位图进行压缩获取需要发送的小块,采用压缩发给用户。用户通过解压显示图片。

五、数据压缩

图片之所以需要压缩,是因为捕捉到的屏幕是一块
位图(bitmap)。

色彩的表示是由R、G、B组成, bitmap包含图片每一个像素点的信息(R、G、B分别占8个二进制位,那么R、G、B的的范围恰好是0-255),32位的bmp位图还用了1字节来作为alpha通道,每一个像素点占32位。24位位图俗称“真彩”,因为保留了所有的信息,所以体积很大。

色彩还有另一种表示的方法(jpeg),是灰度、亮度、对比度,因为人眼睛的特殊,这种标准的图片有一定失真,但是肉眼难以判断。简单的说,由于压缩的原因,这种图片每一个像素点RGB值是由周围一些像素点一起决定的。

本程序中压缩采用了:

1.单遍
霍夫曼编码(Huffman)压缩

2.多遍霍夫曼压缩编码

3.
Run Length编码(游程编码)

4.Run Length&Huffman编码

之前有看过一点计算机图形学, 也做过bmp图片编辑、bmp图片压缩。(秀知识上限了,囧~~~,确实没有好好学过图形学- -#)

六、结束语

看完服务器端,可以说这个程序涉及的知识面还是很广的。win32、网络编程、c++的oop(很少)、位图压缩、汇编等,把服务器端分析完,基本都能猜到客户端是怎么实现的了。

源码下载及界面截图:
http://www.oschina.net/code/snippet_583625_12606
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: