摘要:本文介绍了一种通过 套接字网络编程和 屏幕捕获技术实现的对远程计算机屏幕进行监视的方法。

   关键词:套接字;屏幕 捕捉;远程监视;网络

   前言

  在实际工程中,经常有施工现场和控制中心不在一起的情况,在这种情况一般多由工程技术人员往返穿梭其间来实现对远程施工现场的情况了解和对控制中心的矫正控制。显然这种工作方式的效率是很低下的,没有充分发挥计算机网络的强大优势,其实通过网络编程完全可以使技术人员在控制中心对位于工程现场的远程计算机实施监视和控制。虽然互联网上有不少远程终端控制软件如"超级 间谍"、"冰河"等,但由于其带有 黑软的性质,不能保证其在编程时没有留有其他后门,因此从 计算机安全的角度出发应当自行开发此类软件。为避免本文所述技术被用于制造黑客类软件,本文将不准备对远程终端的控制部分做进一步的介绍,而将重点放在对远程计算机屏幕界面的监视上。 1 数据信息在网络上的传送

  由于本地计算机是通过网络来对远程计算机实施监控,因此需要对网卡进行编程以实现往来于双方的数据信息在网络上的顺畅通讯。可供选择的方案有套接字、邮槽、 命名管道等多种,本文在此选用开发和应用都比较灵活的流式套接字作为网络通讯的基础。考虑到实际情况,远程被监视主机随时为本地监控主机提供屏幕信息的服务,因此整个系统可以划分为两大模块-- 服务器端和 客户机端,分别运行于远程主机和本地监控主机,由客户机向服务器发出连接请求,在建立连接后由服务器定时发送远程屏幕信息给客户机,客户机接收到服务器发来的数据后将其显示在本地主机。

  至于用流式套接字对网络进行编程的主要过程可用下图来表示。服务器方在使用套接字之前,首先必须拥有一个Socket,可用socket()函数 创建之:

sock=socket(AF_INET,SOCK_STREAM,0);

  其中AF_INET 和SOCK_STREAM指定了创建的是采用了TCP/IP地址族的流式套接字。该套接字实际上是提供了一个通信端口,通过这个端口可与任何一个具有套接字端口的计算机实施通信。一旦获取了新的套接字,应立即通过bind()将该套接字与本机上的一个端口建立关联。需要预先对一个指向包含有本机IP地址和端口信息的sockaddr_in结构填充一些必要的信息,如本地端口号和本地主机地址等,并通过bind()将服务器进程在网络 上标识出来:

sockin_s.sin_family=AF_INET;
sockin_s.sin_addr.s_addr=0;
sockin_s.sin_port=htons(PORT);
bind(sock,(LPSOCKADDR)&sockin_s,sizeof(sockin_s));

  在完成接下来的listen()侦听后,需要用accept()等待接收客户端的连接,由于该函数在没有客户端进行申请连接之前会处于阻塞状态,因此需要为其单独开辟一个线程,以免影响到程序整体:

AfxBeginThread(Server,NULL);//创建一个新的线程
……
UINT Server(LPVOID lpVoid)
{
 CSurveillant_ServerView* pView=((CSurveillant_ServerView*)((CFrameWnd*)
 AfxGetApp()->m_pMainWnd)->GetActiveView());
 int nLen=sizeof(SOCKADDR);
 pView->newskt_s= accept(pView->sock,(LPSOCKADDR)& pView->sockin_s,(LPINT)& nLen);
 WSAAsyncSelect(pView->newskt_s,pView->m_hWnd,WM_MSG,FD_CLOSE);
 pView->SetTimer(0,2500,NULL);
 return 1;
}

  在这里通过WSAAsyncSelect()异步选择函数来以异步的形式响应关心的网络事件FD_CLOSE,并在该事件发生时发出自 定义WM_MSG消息,通过响应这个消息可以得之当前与服务器联系的客户机程序已关闭退出,由于服务器部分是运行于远程工程现场的,为了使控制中心的监控程序(客户)在下次发出监控请求时能为其提供服务需要在WM_MSG的消息响应函数里关闭由accept() 所产生的新的套接字newskt_s,并 重新启动该线程等待监控程序的再次连接。在accept()函数成功返回后,就可以在 定时器响应函数里用send() 函数与之建立了连接的监控主机定时发送捕获的远程屏幕信息了。

  作为客户的监控程序,其实现过程要比服务器 简单许多。由于需要接收数据,因此在异步选择函数中需要设定待监测的网络事件为FD_CLOSE和FD_READ。在消息响应函数中可以通过对消息 参数的低位字节进行判断而区分出具体发生是何种网络事件,并对其做出响应的反应。下面是监控端程序网络部分的主要代码:

……
IPaddr=inet_addr(strIP);
sock=socket(AF_INET,SOCK_STREAM,0); //创建套接字
sockin_c.sin_family=AF_INET;
sockin_c.sin_addr.S_un.S_addr=IPaddr;
sockin_c.sin_port=m_Port;
connect(sock,(LPSOCKADDR)&sockin_c,sizeof(sockin_c));//连接服务器
……
WSAAsyncSelect(sock,m_hWnd,WM_MSG,FD_READ|FD_CLOSE);
……

  通过异步选择函数的设定,在有数据到达时会由FD_READ触发WM_MSG消息,并在处理函数中通过调用recv ()将远程主机的屏幕信息从网络接收到缓存,并完成在本地机的重显。通过以上几步,已经初步具备了在远程服务器和本地客户机之间的网络通讯能力,可以完成屏幕信息的网络传送任务。

  对远程计算机屏幕的捕捉和显示

  前面部分的工作只是为整个监控系统提供一个低层的网络数据通讯的能力,也可以说是为现场主机和监控中心提供一个通信用信道。至于本文的中心议题--远程监视工作则需要分别在现场主机和监控中心中完成对屏幕的捕捉和信息的再现。屏幕的捕捉可以采取先获取桌面窗口指针并建立一个与之兼容的设备环境,然后创建一个与桌面窗口指针相兼容的内存位图并以位图的形式将屏幕图像拷贝到新创建的位图之中:

char dot[1572864]; //1024*768*2
CBitmap bmp; //内存位图
CDC wdc; //设备环境
CDC* pDC; //指向桌面窗口的设备环境指针
……
static CWindowDC ddc(GetDesktopWindow()); //引用桌面窗口指针定义对象ddc
pDC=&ddc; //将指针pdc指向ddc
wdc.CreateCompatibleDC(pDC); //建立与ddc兼容的设备环境
bmp.CreateCompatibleBitmap(pDC,1024,768); //建立与ddc兼容的位图
wdc.SelectObject(&bmp); //选择bmp
……
wdc.BitBlt(0,0,1024,768,pDC,0,0,SRCCOPY); //把桌面图像复制到wdc的bmp中

  这时虽以获取到了屏幕的信息,并将其复制到内存位图之中,但此时还不能直接将其发送出去,需要调用CBitmap 类的成员函数GetBitmapBits()来将图像信息从内存位图拷贝到缓存,并通过套接字的send()函数将缓存中存放的屏幕信息通过网络从现场主机发送到控制中心。

  现场主机的屏幕信息在控制中心的再现,基本上是屏幕截取的逆过程:先建立一个同客户区相关的设备环境并建立一个与之兼容的设备环境,然后按位图格式在内存中创建一个与之兼容的内存位图。在从网络接收完一屏信息后,通过CBitmap的成员函数SetBitmapBits()把缓存中的屏幕信息按位图格式拷贝到内存位图,最后完成对内存位图的显示。其主要过程如下:

CDC* pDC=GetDC(); //引用用户窗口指针定义对象pDC
wdc.CreateCompatibleDC(pDC); //建立与pDC兼容的device context
bmp.CreateCompatibleBitmap(pDC,1024,768); //建立与pDC兼容的位图
wdc.SelectObject(&bmp);
……
iReadLen = recv(sock,buffer,60000,0); //从网络接收数据
for(i=0;i<iReadLen;i++)
{
 dot[pointer]=buffer[i];
 pointer++;
 if(pointer==1572864) //判断接收到的信息是否已满一屏
 {
  GetClientRect(&rect);
  bmp.SetBitmapBits(1572864,(LPVOID)dot); //把内存数据复制到bmp中
  //把bmp中图像复制到用户窗口中
  pDC->StretchBlt(0,0,rect.Width(),rect.Height(),&wdc,0,0,1024,768,SRCCOPY);
  pointer=0; //接收完一屏后指针复位,准备接收下一屏
 }
}

   服务程序的自动加载及扩展

  从功能上看,服务端程序只负责为远程客户提供服务,在全部运行期间根本不需要人为的外来干预,因此可以隐藏其界面并将其作成后台服务程序:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
 ……
 cs.cx=200;
 cs.cy=10;
 cs.style=WS_POPUP;
 cs.dwExStyle|=WS_EX_TOOLWINDOW;
 return TRUE;
}

  另外,由于现在计算机多具有通过Modem实现远程唤醒的功能,因此如能使服务程序具备自启动功能将实现远程现场主机的无人值守。自启动有多种方式:在Autoexec.bat、win.ini等文件中加入启动命令、在"启动"菜单里加入指向程序的快捷方式、修改注册表等。其中由于注册表通常被人为改动的机会要小的多,因此通过修改注册表实现自启动是一种比较安全的方法。本文采取的方法是:先通过API函数CopyFile()将服务程序复制到系统目录,然后对HKEY_LOCAL_MACHINE 的Software/Microsoft/Windows/CurrentVersion/Run写入一个字符串键值,该键值的内容是服务程序在系统目录下的全路径:

DWORD type=REG_SZ;
DWORD size=MAX_PATH;
LPCTSTR Rgspath="Software//Microsoft//Windows//CurrentVersion//Run" ;
……
GetSystemDirectory(SysPath,size); //获取系统目录
GetModuleFileName(NULL,CurrentPath,size); //获取程序路径
FileCurrentName = CurrentPath;
FileNewName = lstrcat(SysPath,"//Surveillant.exe");
ret = CopyFile(FileCurrentName,FileNewName,TRUE); //拷贝程序到系统目录
……
//打开注册表
ret=RegOpenKeyEx(HKEY_LOCAL_MACHINE,Rgspath,0,KEY_WRITE, &hKEY);
……
//写入注册表
ret=RegSetValueEx(hKEY,"Surveillant",NULL,type, FileNewName,size);
……
//关闭注册表
RegCloseKey(hKEY);

  至于监控中心对现场主机的远程控制,则主要是通过向对方程序发送用以标识消息的数据并在远程主机接收完毕后用SendMessage()向指定窗口发送消息来完成的,可用CreateProcess();来启动现场主机的程序以响应消息。由于该部分技术亦可用来编写黑客软件,故本文在此不便作进一步的描述。

   小结

  本文主要针对基于流式套接字的低层网络通讯模块和建立在该模块基础之上的屏幕截取和复原技术的设计、实现作了较为详细的介绍。本文所述监控系统在实际应用中取得了较好的效果。使工程技术人员能在控制中心及时了解到位于工程现场的计算机屏幕上的指示图表的动态显示,并根据监视结果作出及时的决策。本文所述程序在Windows 2000 Professional下,由Microsoft Visual C++编译通过。

VC++实现对远程计算机屏幕的监视相关推荐

  1. mfc获取别的计算机是否在线,VC获取并修改计算机屏幕分辨率(MFC)

    //检测当前分辨率 int Width = GetSystemMetrics(SM_CXSCREEN); int Height = GetSystemMetrics(SM_CYSCREEN); DEV ...

  2. mfc改计算机名称,VC获取并修改计算机屏幕分辨率(MFC)

    //检测当前分辨率 int Width = GetSystemMetrics(SM_CXSCREEN); int Height = GetSystemMetrics(SM_CYSCREEN); DEV ...

  3. 任务计划无法连上远程计算机,win7计划任务,找不到远程计算机.docx

    win7计划任务,找不到远程计算机 巧用win7任务计划设置程序自动运行 Windows7任务计划是如何帮我们自动运行程序的? Win7自动运行工作 步骤一:依次打开开始/所有程序/管理工具/任务计划 ...

  4. vnc支持用计算机民远程吗,使用vnc连接远程计算机

    VNC(Virtual Network Computing,虚拟网络计算机),由AT&T实验室于2002年开发的, 是一个远程操控计算机的软件,它能够将远程计算机完整的窗口画面通过网络传输到 ...

  5. RDO远程连接时提示“远程计算机需要网络级别身份验证,而您的计算机不支持该验证解决办法!

    RDO远程连接时提示"远程计算机需要网络级别身份验证,而您的计算机不支持该验证,请联系您的系统管理员或者技术人员来获得帮助" 当服务器重装操作系统后使用RDO远程连接时会出现错误提 ...

  6. 使用远程工具RDO:远程计算机需要网络级别身份验证,而您的计算机不支持该验证解决办法

    查询关于网络级别身份验证的说法: 网络级身份验证是一种在远程桌面服务(RDP服务器)或远程桌面连接(RDP客户端)使用的技术,它要求用户在与服务器创建会话前先进行身份验证.在最初,如果用户打开一个到服 ...

  7. 关机切换用户后显示远程计算机,系统远程关机权限的设置

    系统远程关机权限的设置 发布时间:2009-06-17 00:43:28   作者:佚名   我要评论 在内网环境中,有的人可能同时要管理或操作几台工作站,不用谈其他的管理操作,就连简单的关机操作,如 ...

  8. 远程计算机如果关机咋办,远程关机的详细步骤有哪些?向日葵怎么远程关机?...

    生活节奏的加快,工作的忙碌,你是否有过出差后或者上班后把家里的电脑忘记关机了?一定程度上给人们带来不便,那么是如何实现远程关机的呢?下文就跟着小编详细了解远程关机的步骤. 远程关机的详细步骤有哪些? ...

  9. 剑走偏锋--使用WMI获取远程计算机进程程序集中查毒病毒打造内网安全环境

    剑走偏锋-使用WMI获取远程计算机进程程序 集中查毒病毒打造内网安全环境 作者:高玉涵 时间:2019.04.1815:45 博客:blog.csdn.net/cg_i 作者背景环境参见: <由 ...

最新文章

  1. 对象比较:Comparable 和 Comparator
  2. 马斯克明年送3人到太空站旅游:票价3.8亿,仅剩2席,手慢无
  3. cli2弃用了吗 vue_vue cli - 2 升级到 3的问题汇总
  4. c语言大乐透编译,Excel大乐透摇号vba代码分享,说不定就中百万了呢
  5. OSL创始人登上美国知名电视节目宣传DeFi引关注
  6. Qt那些事0.0.2
  7. python复杂代码示例_6 个例子教你重构 Python 代码
  8. 《程序设计技术》第三章例程
  9. python学习笔记(图形用户界面)
  10. 【MySQL】MySQL-主从复制-集群方案-数据一致性问题解决方案 MySQL备份的各种姿势...
  11. ZK UserGuide(一)理解/userguide/index.zul导航原理
  12. 3dmax2021用哪个vray?大神们都是这样搭配3dmax的渲染器版本的
  13. 噪音测试软件+安卓,分贝噪音测试软件
  14. 为什么登录赛尔号显示服务器未开启,赛尔号之勇者无敌无法打开怎么办 赛尔号之勇者无敌登录不了解决方案...
  15. iOS常用RGB颜色的色值一览表
  16. PicPick Pro v7.0.0 屏幕截图编辑工具解锁全功能单文件版
  17. python之无限浏览网页
  18. JDBC各种jar包下载(免费资源)
  19. 【红包雨】活动红包雨实现逻辑(ionic+springboot)
  20. python json字典模块详解,json.dumps(),json.loads()

热门文章

  1. 互联网晚报 | 3月1日 星期二 |​ 2022年苹果可能推出三款Apple Watch;“国家中小学智慧教育平台”投入试运行...
  2. 作者:宾军志(1976-),男,御数坊(北京)科技咨询有限公司联合创始人。...
  3. 祝贺本刊编委石勇教授入选2016年汤森路透全球高被引科学家
  4. 【项目管理】项目管理计划
  5. 【操作系统】Semaphore处理读者-写者问题
  6. 【Python】处理ConvergenceWarning: lbfgs failed to converge (status=1):STOP: ...
  7. 初识vue之axios的封装
  8. R语言是如何增强数据科学
  9. JavaMail发送邮件的笔记及Demo
  10. 利用unison+inotify 实现数据双向实时同步