源码下载:http://user.qzone.qq.com/58408454/blog/1255252449
//
//*
//*工程: 远程监视器
//*作者: 童方
//*时间: 2009-9-11
//*说明: 1 服务端,即:被监视端
//* 2 未做数据压缩处理(如果您为本例程加入压缩算法或扩展功能,希望您可以发给我一份您更新后的源码)
//* 3 愿我的代码给您带来小小的启发和帮助
//* 4 也希望您给我提供宝贵的意见,互相学习,共同进步
//*
//*联系方式: QQ 58408454 Email shfhere@qq.com
//*
//
#include "stdafx.h"
#include "MonitorServer.h"
#include <afxsock.h>
#include <Afxmt.h>
//#include "../zlib/zlib.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#else //*发行版本将隐藏窗口
#pragma comment (linker, "/ENTRY:mainCRTStartup")
#pragma comment (linker, "/subsystem:windows")
#endif
/
// The one and only application object
CWinApp theApp;
using namespace std;
//*工作线程函数
UINT WorkThread(LPVOID param);
//*抓屏函数
void ProcessScreen();
//*压缩
void ProcessCompress();
//*发送
BOOL ProcessSend(SOCKET sock);
//*发送包头
BOOL SendPackageHead(SOCKET sock);
//*发送位图头信息
BOOL SendBitmapHead(SOCKET sock);
//*发送位图数据
BOOL SendBitmapData(SOCKET sock);
//*发送包尾
BOOL SendPackageTail(SOCKET sock);
//*初始化屏幕信息
void InitScreen();
//*释放屏幕信息资源
void UninitScreen();
//*自定义发送函数
BOOL MySend(SOCKET sock, LPVOID lpData, int nSize);
//*自定义接收函数
BOOL MyReceive(SOCKET sock, LPVOID lpData, int nSize);
//*运行状态标志
BOOL bRunning = TRUE;
//*控制台消息函数
BOOL CtrlHandler(DWORD fdwCtrlType);
//*桌面DC,抓图源DC
CDC DeskDC;
//*内存DC,抓图目标DC
CDC MemDC;
//*内存位图,抓图目标位图
CBitmap MemBitmap;
//*旧位图
CBitmap *OldBitmapPointer = NULL;
//*位图信息
BITMAPINFOHEADER BitmapInfoHeader;
//*位图数据缓存
LPBYTE BitmapBuffer = NULL;
//*压缩数据缓存
LPBYTE ZipBuffer = NULL;
//*位图数据缓存大小
DWORD BitmapBufferSize = 0;
//*压缩数据缓存大小
DWORD ZipBufferSize = 0;
//*位图宽高(屏幕分辨率)
WORD BitmapWidth = 0;
WORD BitmapHeight = 0;
//*客户线程临界区(避免多客户连接时,缓存冲突)
CCriticalSection csClient;
//*服务SOCKET,用于监听客户连接
SOCKET sockListen = INVALID_SOCKET;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
//*设置窗口标题
SetConsoleTitle(_T("Remote Desktop Server"));
//*设置窗口消息函数
SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);
//*初始化MFC库,使项目支持MFC
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("初始化MFC失败.") << endl;
nRetCode = 1;
return nRetCode;
}
//*初始化SOCKET
if (!AfxSocketInit())
{
cerr << _T("初始化套接字失败.") << endl;
nRetCode = 1;
return nRetCode;
}
//*初始化抓屏信息
InitScreen();
//*建立监听套接字
sockListen = socket(AF_INET, SOCK_STREAM, 0);
if(sockListen == INVALID_SOCKET)
{
cerr << _T("Fatal Error: Create socket failed") << endl;
nRetCode = 1;
return nRetCode;
}
SOCKADDR_IN SockAddr;
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(3517);
SockAddr.sin_addr.s_addr = INADDR_ANY;
int SockAddrLen = sizeof(sockaddr);
//*绑定套接字
if(bind(sockListen, (SOCKADDR*)&SockAddr, SockAddrLen) == SOCKET_ERROR)
{
cerr << _T("Fatal Error: Bind socket failed") << endl;
nRetCode = 1;
return nRetCode;
}
SOCKADDR_IN sa;
int naddr = sizeof(SOCKADDR);
//*启动监听
listen(sockListen, 5);
while(bRunning) //*bRunning为真时,一直等候客户连接
{
//*等待客户连接
SOCKET sock = accept(sockListen, (SOCKADDR*)&sa, &naddr);
//*接受客户后,为该客户启动一工作线程
AfxBeginThread(WorkThread, (LPVOID)sock);
}
//*释放抓屏资源
UninitScreen();
return nRetCode;
}
//*工作线程
UINT WorkThread(LPVOID param)
{
SOCKET sock = (SOCKET)param;
int nZero = 0;
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&nZero, sizeof(int));
while(bRunning) //*bRunning为真时,一直向客户发送屏幕图象
{
//*资源锁,为当前客户发数据时,其他客户线程等候
csClient.Lock();
//*抓屏
ProcessScreen();
//*压缩
ProcessCompress();
//*发送
if(!ProcessSend(sock))
{
//*发送失败时,意味客户断开,不管什么原因,退出工作线程
//*退出前解开资源锁
csClient.Unlock();
break;
}
//*处理完成后,解锁
csClient.Unlock();
//*等候一段时间再继续发送
Sleep(30);
}
//*关闭套接字
closesocket(sock);
//*结束线程
AfxEndThread(0);
return 0;
}
void ProcessScreen()
{
//*抓屏
OldBitmapPointer = (CBitmap*)MemDC.SelectObject(&MemBitmap);
MemDC.BitBlt(0, 0, BitmapWidth, BitmapHeight, &DeskDC, 0, 0, SRCCOPY);
MemDC.SelectObject(OldBitmapPointer);
BITMAP bm;
MemBitmap.GetBitmap(&bm);
//*检查缓存
if(!BitmapBuffer)
{
//*初始化缓存
BitmapBufferSize = bm.bmWidthBytes * bm.bmHeight;
BitmapBuffer = new BYTE[BitmapBufferSize];
ZipBufferSize = BitmapBufferSize; //*compressBound(BitmapBufferSize);
ZipBuffer = new BYTE[ZipBufferSize];
}
//*处理位图信息头
BitmapInfoHeader.biBitCount = bm.bmBitsPixel;
BitmapInfoHeader.biClrImportant = 0;
BitmapInfoHeader.biClrUsed = 0;
BitmapInfoHeader.biCompression = 0;
BitmapInfoHeader.biHeight = bm.bmHeight;
BitmapInfoHeader.biPlanes = 1;
BitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
BitmapInfoHeader.biSizeImage = BitmapBufferSize;
BitmapInfoHeader.biWidth = bm.bmWidth;
BitmapInfoHeader.biXPelsPerMeter = 0;
BitmapInfoHeader.biYPelsPerMeter = 0;
//*获取位图的图象数据
GetDIBits(MemDC.GetSafeHdc(), (HBITMAP)MemBitmap.GetSafeHandle(), 0, BitmapInfoHeader.biHeight, (LPVOID)BitmapBuffer, (LPBITMAPINFO)&BitmapInfoHeader, DIB_RGB_COLORS);
}
void ProcessCompress()
{
//*处理压缩,我原来用zlib压缩,出现一些问题,固此例程,未做数据压缩处理
// if(ZipBuffer)
// compress(ZipBuffer, &ZipBufferSize, (LPBYTE)BitmapBuffer, BitmapBufferSize);
}
BOOL ProcessSend(SOCKET sock)
{
//*发送包头
if(!SendPackageHead(sock)) return FALSE;
//*发送位图头
if(!SendBitmapHead(sock)) return FALSE;
//*发送位图数据
if(!SendBitmapData(sock)) return FALSE;
//发送包尾
if(!SendPackageTail(sock)) return FALSE;
return TRUE;
}
BOOL SendPackageHead(SOCKET sock)
{
//*由字符串 TF Remote Package Head... 开始的包头 TF就是(童方)嘛^0^
char PackageHead[] = "TF Remote Package Head.../0";
return MySend(sock, PackageHead, strlen(PackageHead));
}
BOOL SendBitmapHead(SOCKET sock)
{
//*发送位图信息头,为自订义的信息,包括我想要发到客户端的消息
//*位图缓存大小
if(MySend(sock, &BitmapBufferSize, 4) == FALSE)
return FALSE;
//*压缩后位图缓存大小
if(MySend(sock, &ZipBufferSize, 4) == FALSE)
return FALSE;
//*位图宽度
if(MySend(sock, &BitmapWidth, 2) == FALSE)
return FALSE;
//*位图高度
if(MySend(sock, &BitmapHeight, 2) == FALSE)
return FALSE;
//*位图信息头对象
if(MySend(sock, &BitmapInfoHeader, sizeof(BITMAPINFOHEADER)) == FALSE)
return FALSE;
return TRUE;
}
BOOL SendBitmapData(SOCKET sock)
{
//*如果处理压缩后,则发送 ZipBuffer 缓存中的数据
// return MySend(sock, ZipBuffer, ZipBufferSize);
//*这里发送原始位图数据
return MySend(sock, BitmapBuffer, BitmapBufferSize);
}
BOOL SendPackageTail(SOCKET sock)
{
//*由字符串 TF Remote Package Tail... 结束的包尾 TF就是(童方)嘛^0^
char PackageTail[] = "TF Remote Package Tail.../0";
return MySend(sock, PackageTail, strlen(PackageTail));
}
void InitScreen()
{
//*获取屏幕的宽和高
BitmapWidth = GetSystemMetrics(SM_CXSCREEN);
BitmapHeight = GetSystemMetrics(SM_CYSCREEN);
//*建立屏幕DC,内存DC,内存位图
DeskDC.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
MemDC.CreateCompatibleDC(&DeskDC);
MemBitmap.CreateCompatibleBitmap(&DeskDC, BitmapWidth, BitmapHeight);
//*初始化缓存结构
BitmapBuffer = NULL;
ZipBuffer = NULL;
BitmapBufferSize = 0;
ZipBufferSize = 0;
}
void UninitScreen()
{
//*释放内存DC,内存位图,屏幕DC
MemDC.DeleteDC();
DeskDC.DeleteDC();
MemBitmap.DeleteObject();
//*释放位图缓存,压缩缓存
if(BitmapBuffer)
delete [] BitmapBuffer;
if(ZipBuffer)
delete [] ZipBuffer;
}
BOOL MySend(SOCKET sock, LPVOID lpData, int nSize)
{
//*自订义数据发送,直到发送完成时才返回
char* Buf = (char*)lpData;
int nLen = nSize;
int n;
int nIndex = 0;
while(nLen > 0)
{
n = send(sock, &Buf[nIndex], nLen, 0);
if(n == SOCKET_ERROR)
return FALSE;
nIndex += n;
nLen -= n;
}
return TRUE;
}
BOOL MyReceive(SOCKET sock, LPVOID lpData, int nSize)
{
//*自订义数据接收,直到接收到指定大小的数据后才返回
char* Buf = (char*)lpData;
int nLen = nSize;
int n;
int nIndex = 0;
while(nLen > 0)
{
n = recv(sock, &Buf[nIndex], nLen, 0);
if(n == SOCKET_ERROR)
return FALSE;
nIndex += n;
nLen -= n;
}
return TRUE;
}
BOOL CtrlHandler(DWORD fdwCtrlType)
{
switch (fdwCtrlType)
{
// Handle the CTRL+C signal.
case CTRL_C_EVENT:
return TRUE;
// CTRL+CLOSE: confirm that the user wants to exit.
case CTRL_SHUTDOWN_EVENT:
case CTRL_CLOSE_EVENT:
shutdown(sockListen, 2);
closesocket(sockListen);
bRunning = FALSE;
return TRUE;
// Pass other signals to the next handler.
case CTRL_BREAK_EVENT:
case CTRL_LOGOFF_EVENT:
default:
return FALSE;
}
}