详细分析如下: 1.Wm_hooks截获消息并转化为自定义的消息发送给WMHooksThread线程处理。 Wm_hooks自定义的消息: UINT WM_HK_WindowChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.WindowChanged")) UINT WM_HK_WindowClientAreaChanged = UINT WM_HK_WindowBorderChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.WindowBorderChanged")) UINT WM_HK_RectangleChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.RectangleChanged")) UINT WM_HK_CursorChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.CursorChanged")) 钩子截获到消息以后,把它转化为自定义的消息,然后发送给WMHooksThread线程处理,消息转化如下: 边框更新消息:WM_NCPAINT,WM_NCACTIVATE 客户区域更新消息:BM_SETCHECK, BM_SETSTATE,EM_SETSEL,WM_CHAR,WM_ENABLE,WM_KEYUP,WM_LBUTTONUP,WM_MBUTTONUP,WM_PALETTECHANGED,WM_RBUTTONUP,WM_SYSCOLORCHANGE,WM_SETTEXT。 窗口改变消息:WM_HSCROLL,WM_VSCROLL,482,485。 矩形区更新消息:WM_DESTROY 窗口客户区消息:WM_PAINT 鼠标消息:WM_NCMOUSEMOVE,WM_MOUSEMOVE 2 . WMHooksThread 中用SimpleUpdateTracker new_changes记录新的更新区域 WMHooksThread::run() 函数中先判断出矩形区域改变的大小,然后调用NotifyHooksRegion(const Region&r)把改变的区域记录到SimpleUpdateTracker new_changes中。 NotifyHooksRegion(const Region&r) { Lock l(hook_mgr_lock) std::list<WMHooks*>::iterator i for (i=hooks.begin()i!=hooks.end()i++) { (*i)->new_changes.add_changed(r) if (!(*i)->notified) {(*i)->notified = true PostMessage((*i)->getHandle(), WM_USER, 0, 0)// 把消息通知到clipper见下面一个处理函数 } } } 3.把更新区域拷贝到SDisplay中 rfb::win32::WMHooks::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_USER: {Sleep(0) Lock l(hook_mgr_lock) notified = false new_changes.get_update(*clipper)//把更新通知到clipper中new_changes.clear() } break } return MsgWindow::processMessage(msg, wParam, lParam) } Cliper在下面设置 rfb::win32::WMHooks::setUpdateTracker(UpdateTracker* ut) { if (clipper) delete clipper clipper = new ClippedUpdateTracker(*ut) clipper->set_clip_region(clip_region) return AddHook(this) } UpdateTracker* ut 为void SDisplay::start(VNCServer*vs)中设置 core->using_hooks = core->wm_hooks.setUpdateTracker(this) 4.把SDisplay中记录的数据传给VNCServerST 对象 在 SDisplay::processEvent(HANDLE event) { try_update = flushChangeTracker() || try_update//把变化的区域拷贝到VNCServerST中if (try_update) server->tryUpdate() //把更新发送给服务器 } flushChangeTracker()实现如下: bool SDisplay::flushChangeTracker() { if (change_tracker.is_empty()) return false change_tracker.translate(screenRect.tl.negate()) change_tracker.get_update(*server)//server 实际指向VNCServerST 对象该函数把SDisplay中的更新拷贝到VNCServerST中。 change_tracker.clear() return true } 两种数据更新方式:Push机制和Pull机制 Push: SdisplayCore 中IntervalTimer cursorTimer定时器,每隔10ms尝试着检查一下是否有更新,如果有更新就发送更新给客户端
第一步: LRESULT SDisplayCore::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) { case TIMER_CURSOR: display->triggerUpdate()//SDisplay* display} 第二步: void SDisplay::triggerUpdate() { if (core) SetEvent(updateEvent)//使事件对象为受信状态 } 第三步: SDisplay::processEvent(HANDLE event) { if (event == updateEvent) { if (try_update) server->tryUpdate()// VNCServer* server指针 指向子类VNCServerST } } 第四步:向每一个连接的客户端发送更新 void VNCServerST::tryUpdate() { std::list<VNCSConnectionST*>::iterator ci, ci_next for (ci = clients.begin()ci != clients.end()ci = ci_next) { ci_next = cici_next++ (*ci)->writeFramebufferUpdateOrClose() } }
第五步: void VNCSConnectionST::writeFramebufferUpdateOrClose() { try { writeFramebufferUpdate() } catch(rdr::Exception &e) { close(e.str()) } } 第六步:SimpleUpdateTracker updates对象记录更新的区域,如果屏幕有更新则发送更新 void VNCSConnectionST::writeFramebufferUpdate(){ if (!update.is_empty() || writer()->needFakeUpdate() || drawRenderedCursor) { int nRects = update.numRects() + (drawRenderedCursor ? 1 : 0) writer()->writeFramebufferUpdateStart(nRects) Region updatedRegion writer()->writeRects(update, &image_getter, &updatedRegion)// SmsgWriter *updates.subtract(updatedRegion) if (drawRenderedCursor)writeRenderedCursorRect() writer()->writeFramebufferUpdateEnd() requested.clear() }
} 第七步:利用RFB协议发送更新 void SMsgWriterV3::writeFramebufferUpdateStart(int nRects) { startMsg(msgTypeFramebufferUpdate) os->pad(1) if (wsccb) nRects++ if (needSetDesktopSize) nRects++ os->writeU16(nRects) nRectsInUpdate = 0 nRectsInHeader = nRects if (wsccb) { wsccb->writeSetCursorCallback() wsccb = 0 } } Poll机制:客户端通过发送更新请求,请求更新某一个区域。 第一步:读取到一个更新某一个区域的请求 void SMsgReaderV3::readMsg() { case msgTypeFramebufferUpdateRequest: readFramebufferUpdateRequest()break } 第二步:调用网络事件处理对象handler处理事件 void SMsgReader::readFramebufferUpdateRequest() { bool inc = is->readU8() int x = is->readU16() int y = is->readU16() int w = is->readU16() int h = is->readU16() endMsg() handler->framebufferUpdateRequest(Rect(x, y, x+w, y+h), inc)//handler 为 SMsgHandler* handler指针 是指向VNCSConnectionST对象 } 第三步: void VNCSConnectionST::framebufferUpdateRequest(const Rect&r,bool incremental) { if (!(accessRights &AccessView)) return SConnection::framebufferUpdateRequest(r, incremental) Region reqRgn(r) requested.assign_union(reqRgn) if (!incremental) {updates.add_changed(reqRgn) server->comparer->add_changed(reqRgn) } writeFramebufferUpdate() } 第四步:SimpleUpdateTracker updates对象记录更新的区域,如果屏幕有更新则发送更新 void VNCSConnectionST::writeFramebufferUpdate(){ if (!update.is_empty() || writer()->needFakeUpdate() || drawRenderedCursor) { int nRects = update.numRects() + (drawRenderedCursor ? 1 : 0) writer()->writeFramebufferUpdateStart(nRects) Region updatedRegion writer()->writeRects(update, &image_getter, &updatedRegion)// SmsgWriter *updates.subtract(updatedRegion) if (drawRenderedCursor)writeRenderedCursorRect() writer()->writeFramebufferUpdateEnd() requested.clear() } } 第五步:利用RFB协议发送更新 void SMsgWriterV3::writeFramebufferUpdateStart(int nRects) { startMsg(msgTypeFramebufferUpdate) os->pad(1) if (wsccb) nRects++ if (needSetDesktopSize) nRects++ os->writeU16(nRects) nRectsInUpdate = 0 nRectsInHeader = nRects if (wsccb) { wsccb->writeSetCursorCallback() wsccb = 0 } }
你看一下吧 我也是给你找的!
vnc的源码安装与使用!!!VNC的原码安装与使用
下载VNC Server与VNC viewer.
VNC Server下载地址:http://www.linuxeden.com/download/softdetail.php?softid=744
VNC viewer下载地址:http://download.pchome.net/php/dl.php?sid=2603
文章分为两部分:1〉被控端 Redhat A3主控端Windows 2000
2〉被控端 Windows 2000 主控端Redhat A3
一、被控端 Redhat A3主控端Windows 2000
1.安装vnc-3.3.7-x86_linux.tar.gz
t ar -zxvf vnc-3.3.7-x86_linux.tar.gz
cd vnc-3.3.7-x86_linux
./vncinstall /usr/bin /usr/local/share/man #前一个路径是vnc的执行文件路径(可更改) 后一个是vnc man的安装路径
安装winvnc.exe
2.在Linux上启动VNC Server
执行vncserver命令:
[root@linux root]# vncserver
You will require a password to access your desktops.
Password: ----为了不想任何人都可以任意遥控此计算机。因此当第
Verify: ---1次启动VNC server时,会要求设置网络遥控的密码。
New ‘X’ desktop is linux:1 ----一定要记住这一行稍后会用到。
Creating default startup script /root/.vnc/xstartup
Starting applications specified in /root/.vnc/xstartup
Log file is /root/.vnc/linux:1.log
(经上述步骤后,便已启动了VNC Server。如果你想要更改VNC Server的密码,只要执行vncpasswd命令即可。)
3.在Microsoft Windows上运行VNC Viewer
直接运行“vncviewer.exe”,系统会出现”Connection details”对话框。
在“Connection details”对话框中的“VNC server”文本框中输入VNC Server的IP地址(或主机名及显示装置编号,(请看3。在Linux上 启动VNC server的这一行,New ‘X’ desktop is linux:1 得到此信息),例如:192.168.0.1:1(冒号后面的1是执行VNC Server生成的 显示装置编号),
如图1
单击“OK”按钮后,VNC Server即会开始检查所输入的信息,若是信息错误,系统会出现“Failed to connect to server ”的错误信息:如图2
若是信息正确,则会接着出现“VNC Authentication”对话框。如图3
若是在“VNC Authentication”对话框中输入的密码正确,就可以成功地打开Linux的桌面窗口。如图4
4. 从浏览器远程遥控。
启动VNC Server 后直接打开浏览器,在地址栏中输入被控端的网址或IP地址,并在网址后加上“:5800+显示编号”的端口号即可操控该计 算机。
如图5
例如:http://192.168.01.:5801 (如果显示编号为1,一般第一次设置的显示编号都是1,就用5800+1=5801。)
如图6
如图7
5.vnc默认连接的TWM桌面,可以修改/root/.vnc/xstartup文件,更改连接的桌面。把最后一行 twm&改成 gnome-session&or kde&
二、被控端 Windows 2000 主控端Redhat A3
1.在windows 2000 中运行vnc server ,起来之后右键点击vnc server的图标--〉properties 出现vnc server 的属性配置界面。
如图8
在password后输入自己的密码,并把Auto的勾去掉,并写一个显示装置编号,我的为1。点ok退出。
2.在LINUX中输入vncviewer,出现如图,输入vnc server 的ip+显示装置编号(192.168.0.2:1) 回车出现如图:
如图9
如图10
输入刚才在password后的密码,就会出现windows 2000的界面了!
欢迎分享,转载请注明来源:夏雨云
评论列表(0条)