远程监视器(服务端)

来源:互联网 发布:关于水文地质软件 编辑:程序博客网 时间:2024/06/05 18:26

源码下载: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;
    }
}

原创粉丝点击