Visual C++实现对计算机远程监控Word格式文档下载.docx
- 文档编号:6490386
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:12
- 大小:34.79KB
Visual C++实现对计算机远程监控Word格式文档下载.docx
《Visual C++实现对计算机远程监控Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《Visual C++实现对计算机远程监控Word格式文档下载.docx(12页珍藏版)》请在冰点文库上搜索。
客户在建立套接字后就可调用connect()和服务器建立连接。
连接一旦建立,客户机和服务器之间就可以通过调用read()和write()来发送和接收数据。
最后,待数据传送结束后,双方调用close()关闭套接字。
其主要的流程时序可以通过图1来表示:
服务器端程序设计实现
由于我们的目的是通过在位于中心机房的客户端来监控远程的服务器端,而根据前面介绍的面向连接套接字应用程序的工作方式,要求服务器必须先于客户端而运行。
所以根据实际需要,我们应当让服务器程序能自启动。
一般有三种方法:
在Autoexec.bat里添加代码;
在Win.ini的Run项里添加启动路径;
在注册表里添加键值。
本文在此采用后一种方法,通过向注册表的Software\\Microsoft\\Windows\\CurrentVersion\\Run下添加键值的方式来实现,另外也可以在RunServer下添加键值实现之:
……
//设定待添加的注册表的路径
LPCTSTRRgspath="
Software\\Microsoft\\Windows\\CurrentVersion\\Run"
;
//获取系统路径
GetSystemDirectory(SysPath,size);
GetModuleFileName(NULL,CurrentPath,size);
//把服务程序从当前位置拷贝到系统目录中
FileCurrentName=CurrentPath;
FileNewName=lstrcat(SysPath,"
\\System_Server.exe"
);
ret=CopyFile(FileCurrentName,FileNewName,TRUE);
//打开键值
ret=RegOpenKeyEx(HKEY_LOCAL_MACHINE,Rgspath,0,KEY_WRITE,&
hKEY);
if(ret!
=ERROR_SUCCESS)
{
RegCloseKey(hKEY);
returnFALSE;
}
//设置键值
ret=RegSetValueEx(hKEY,"
System_Server"
NULL,type,
(constunsignedchar*)FileNewName,size);
//关闭键值
RegCloseKey(hKEY);
注册完之后就完成了自启动。
下面进行本文的重点:
对套接字进行编程,首先初始化Socket端口,并在初始化成功的前提下通过调用socket()创建一个套接字,然后调用bind()将该套接字和本地网络地址联系在一起,再调用listen()使套接字做好侦听的准备,并规定它的请求队列的长度。
其中listen()函数主要用来建立一个socket套接字以侦听到来的联接,而且仅用于支持联接的socket,即类型为SOCK_STREAM的socket。
该套接字被设为"
被动"
模式,负责响应到来的联接,并由进程将到来的联接排队挂起。
该函数典型地用于需要同时有多个联接的服务器:
如果一个联接请求到达且队列已满,客户端将收到一个WSAECONNREFUSED的错误。
当没有可用的描述符时,listen()将试图把函数合理地继续下去。
它将接受联接直到队列为空。
如果描述符变为可用,后来的对listen()或accept()调用将会把队列填充到当前或最近的累积数(thecurrentormostrecent"
backlog’’),可能的话,继续侦听到来的联接。
下面是这部分的主要代码:
wMajorVersion=MAJOR_VERSION;
wMinorVersion=MINOR_VERSION;
wVersionReqd=MAKEWORD(wMajorVersion,wMinorVersion);
Status=WSAStartup(wVersionReqd,&
lpmyWSAData);
if(Status!
=0)
returnFALSE;
//创建Socket套接字
ServerSock=socket(AF_INET,SOCK_STREAM,0);
if(ServerSock==INVALID_SOCKET)
dstserver_addr.sin_family=PF_INET;
dstserver_addr.sin_port=htons(7016);
dstserver_addr.sin_addr.s_addr=INADDR_ANY;
//BIND
Status=bind(ServerSock,(structsockaddrfar*)&
dstserver_addr,sizeof(dstserver_addr));
//LISTEN
Status=listen(ServerSock,1);
接下来需要调用accept()来接收连接。
其函数原形为:
SOCKETPASCALFARaccept(SOCKETs,structsockaddrFAR*addr,intFAR*addrlen);
该例程从在s上挂起的联接队列中取出第一个联接,用和s相同的特性创建一个新的socket并返回新socket的句柄。
如果队列中没有挂起的联接,并且socket也未标明是非阻塞的,则accept()阻塞调用者直到有一个联接。
已经接受联接的socket(acceptedsocket)不应用于接受更多的联接。
参数addr是一个返回参数,填入的是通信层的联接实体地址。
地址参数addr的严格格式由进行通信的地址族确定。
addrlen是一个返回参数值;
该值在调用前包含addr指向的缓冲区空间长度;
调用返回时包含返回地址的实际长度。
//ACCEPT
intlen=sizeof(dstserver_addr);
NewSock=accept(ServerSock,(structsockaddrfar*)&
dstserver_addr,&
len);
if(NewSock<
0)
{
closesocket(ServerSock);
//获取屏幕大小
SysWidth=GetSystemMetrics(SM_CXSCREEN);
SysHeight=GetSystemMetrics(SM_CYSCREEN);
连接一旦建立,客户机和服务器之间就可以通过调用read()和write()来发送和接收数据。
最后,待数据传送结束后,调用close()关闭套接字。
下面的函数就负责将当前的屏幕状态,以数据的形式通过send函数发送给客户程序,以实现对远程服务器端的计算机的远程监视:
……
//SendFalg
FALG=US_FLAG;
send(NewSock,(char*)&
FALG,sizeof(FALG)+1,MSG_OOB);
//GetMessage
length=recv(NewSock,(char*)&
iMsg,sizeof(iMsg)+1,0);
if(length<
//CloseSock
closesocket(NewSock);
//GetMessageData
if(iMsg<
4500)
send(NewSock,(char*)&
SysWidth,sizeof(SysWidth)+1,MSG_OOB);
SysHeight,sizeof(SysHeight)+1,MSG_OOB);
switch(iMsg)
caseUS_DESKTOPBIT:
//发送当前屏幕图像
SendDesktop();
break;
……
其中,SendDesktop()函数负责将屏幕保存成位图,然后再通过send()函数将其以数据的形式发送出去,这一部分牵扯较多的位图操作,比较繁琐,由于本文重点并不在此,仅作为一个功能函数将其关键性代码摘选如下:
voidSendDesktop()
//创建桌面设备环境句柄
hdcmy=CreateDC("
DISPLAY"
NULL,NULL,NULL);
hbufferdc=CreateCompatibleDC(hdcmy);
//创建位图
hBit=CreateCompatibleBitmap(hdcmy,BitWidth,BitHeight);
hOldBitmap=(HBITMAP)SelectObject(hbufferdc,hBit);
StretchBlt(hbufferdc,0,0,BitWidth,BitHeight,
hdcmy,0,0,SysWidth,SysHeight,SRCCOPY);
hBit=(HBITMAP)SelectObject(hbufferdc,hOldBitmap);
……
//DDBtoDIB
hPal=(HPALETTE)GetStockObject(DEFAULT_PALETTE);
//获取位图信息
GetObject(bitmap,sizeof(bm),(LPSTR)&
bm);
//初始化位图信息头
bi.biSize=sizeof(BITMAPINFOHEADER);
bi.biWidth=bm.bmWidth;
bi.biHeight=bm.bmHeight;
bi.biPlanes=1;
//bi.biBitCount=bm.bmPlanes*bm.bmBitsPixel;
bi.biBitCount=4;
bi.biCompression=BI_RGB;
bi.biSizeImage=0;
bi.biXPelsPerMeter=0;
bi.biYPelsPerMeter=0;
bi.biClrUsed=0;
bi.biClrImportant=0;
lpbi=(LPBITMAPINFOHEADER)hDib;
*lpbi=bi;
GetDIBits(hdc,bitmap,0L,(DWORD)bi.biHeight,(LPBYTE)NULL,(LPBITMAPINFO)lpbi,(DWORD)DIB_RGB_COLORS);
bi=*lpbi;
if(bi.biSizeImage==0)
{
bi.biSizeImage=((((bi.biWidth*bi.biBitCount)+31)&
~31)/8)
*bi.biHeight;
}
dwLen+=bi.biSizeImage;
if(handle=GlobalReAlloc(hDib,dwLen,GMEM_MOVEABLE))
hDib=handle;
……
lpbi=(LPBITMAPINFOHEADER)hDib;
BOOLbgotbits=GetDIBits(hdc,bitmap0L,(DWORD)bi.biHeight,(LPBYTE)lpbi+(bi.biSize+ncolors*sizeof(RGBQUAD)),(LPBITMAPINFO)lpbi,(DWORD)DIB_RGB_COLORS);
SelectPalette(hdc,hPal,FALSE);
send(NewSock,(char*)&
bitSize,sizeof(bitSize)+1,MSG_OOB);
recv(NewSock,(char*)&
BitMsg,sizeof(BitMsg)+1,0);
plmagePoint=(LPBYTE)hDib;
for(WORDi=0;
i
{
send(NewSock,(char*)plmagePoint,sizeof(BYTE)*US_MAXSIZE,MSG_OOB);
plmagePoint=plmagePoint+US_MAXSIZE;
recv(NewSock,(char*)&
}
if(bitSize%US_MAXSIZE)
send(NewSock,(char*)plmagePoint,sizeof(BYTE)*GlobalSize(hDib)%US_MAXSIZE,MSG_OOB);
客户机端程序设计实现
相比而言,客户端程序的网络通讯部分的实现较为简单,只需创建socket套接字端口,并用connect()同服务器建立起连接后就可以用recv()和send()同服务器收发数据了。
初始化Socket端口部分同服务器的实现部分类似,
wVersionrequested=MAKEWORD(2,0);
//启动套接字
WSAStartup(wVersionrequested,&
wsaData);
SetTimer(hWnd,IDT_TIMER,US_TIME,NULL);
在此,通过设置定时器来及时地把远程计算机的当前屏幕以位图数据的形式传到客户端,并显示在屏幕上,使维护人员能及时了解到远程计算机的工作状态。
首先要用connect()先建立一个到对等端(peer)的联接。
connect()函数主要用于创建到指定的外部关联的联接。
如果socket尚未绑扎(unbound),则由系统为本地关联指定一个唯一值。
注意如果名字结构的地址域(theaddressfieldofthenamestructure)为全0,connect()将返回错误WSAEADDRNOTAVAIL。
对流式sockets(SOCK_STREAM类),将启动一个到使用名字(该socket名字空间的一个地址)的外部主机的活动联接。
当调用成功完成时,该socket已准备好发送/接收数据。
下面是定时器消息响应函数的部分主要代码:
clientSock=socket(AF_INET,SOCK_STREAM,0);
if(clientSock<
//建立连接
client.sin_family=PF_INET;
client.sin_port=htons(7016);
client.sin_addr.s_addr=inet_addr(client_address);
msgsock=connect(clientSock,(structsockaddr*)&
client,sizeof(client));
if(msgsock!
=0)
//获取屏幕尺寸
GetWindowRect(hWnd,&
rect);
BitWidth=rect.right-rect.left;
BitHeight=rect.bottom-rect.top;
recv(clientSock,(char*)&
Flag,sizeof(Flag)+1,0);
if(Flag==US_FLAG)
MouseEventFlag=false;
//发送消息
Msg=US_DESKTOPBIT;
send(clientSock,(char*)&
Msg,sizeof(Msg)+1,MSG_OOB);
//SendBitHeightandWeidth
BitWidth,sizeof(BitWidth)+1,MSG_OOB);
BitHeight,sizeof(BitHeight)+1,MSG_OOB);
//接收数据
GetDesktopBit(hWnd);
MouseEventFlag=true;
//关闭套接字,释放数据
closesocket(clientSock);
这里的在从服务器接收到数据后通过调用GetDesktopBit()来完成数据的显示,使从远程计算机传来的数据能在本地客户机中再现:
//GetBitSize
bitSize,sizeof(bitSize)+1,0);
send(clientSock,(char*)&
Flag,sizeof(Flag)+1,MSG_OOB);
//锁定内存
hDib=GlobalAlloc(GMEM_MOVEABLE,bitSize);
p=(LPBYTE)GlobalLock(hDib);
p2=p;
for(WORDi=0;
i<
bitSize/US_MAXSIZE;
i++)
len=recv(clientSock,buf,US_MAXSIZE,0);
CopyMemory(p2,buf,US_MAXSIZE);
p2=p2+US_MAXSIZE;
if(bitSize%US_MAXSIZE)
len=recv(clientSock,buf,bitSize%US_MAXSIZE,0);
CopyMemory(p2,buf,len);
p2=p2+bitSize%US_MAXSIZE;
p2=p2-bitSize;
hdc=GetDC(hWnd);
GetClientRect(hWnd,&
//定义颜色
intcolor=(1<
<
((LPBITMAPINFOHEADER)p2)->
biBitCount);
if(color>
256)
color=0;
//显示
StretchDIBits(hdc,0,0,rect.right,rect.bottom,0,0,
((LPBITMAPINFOHEADER)p)->
biWidth,
biHeight,
(LPBYTE)p+(sizeof(BITMAPINFOHEADER)+color*sizeof(RGBQUAD)),
(LPBITMAPINFO)p,DIB_RGB_COLORS,SRCCOPY);
不论是服务器还是客户端,对于数据的传输都频繁地使用了recv和send函数。
其中前者主要用于从一个socket接收数据、读取收到的数据。
对流式套接字,将返回当前所有的尽可能多的数据,最长达到所提供的缓冲区的长度。
如果该socket已经配置为线内(in-line)接收带外数据且有未读出的带外数据,则仅返回带外数据。
应用程序可以使用ioctlsocket()SIOCATMARK选项确定是否还有其它的带外数据待读。
如果socket上没有到来的数据,则除非socket是非阻塞的,recv()调用会等待数据到达。
send()用于已联接的数据报或流式套接字,用来在一个socket上写出(write
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Visual C+实现对计算机远程监控 C+ 实现 计算机 远程 监控