本系統實現了基於局域網的遠程桌面實時查看功能,採用 C/S 架構:
核心技術棧:MFC CSocket、GDI 截圖、位圖網絡傳輸、定時器驅動更新。
void CEmployerSeverDlg::CatchScreen() {
CDC dc;
dc.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
CBitmap bm;
int Width = GetSystemMetrics(SM_CXSCREEN);
int Height = GetSystemMetrics(SM_CYSCREEN);
bm.CreateCompatibleBitmap(&dc, Width, Height);
CDC tdc;
tdc.CreateCompatibleDC(&dc);
CBitmap* pOld = tdc.SelectObject(&bm);
tdc.BitBlt(0, 0, Width, Height, &dc, 0, 0, SRCCOPY);
tdc.SelectObject(pOld);
// 獲取位圖信息頭
BITMAP btm;
bm.GetBitmap(&btm);
int size = btm.bmWidthBytes * btm.bmHeight;
// 分配緩衝區並提取像素數據
lpData = new char[size];
BITMAPINFOHEADER bih = {0};
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = btm.bmWidth;
bih.biHeight = btm.bmHeight;
bih.biPlanes = 1;
bih.biBitCount = btm.bmBitsPixel;
bih.biCompression = BI_RGB;
bih.biSizeImage = size;
GetDIBits(dc.m_hDC, bm, 0, bih.biHeight, lpData, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
}
關鍵點:使用 GetDIBits 直接獲取設備無關位圖(DIB)數據,避免中間文件 I/O,提升傳輸效率。
採用簡易雙階段協議:
BITMAP 結構,24 字節)void CBossSeeClientView::OnGetScreen() {
if (!m_pRecBMPSocket) return;
// 1. 請求幀數據
m_pRecBMPSocket->Send("B", 30); // 請求 BITMAP 信息頭
// 2. 接收 BITMAP 信息頭
BITMAP btm;
int ret = m_pRecBMPSocket->Receive(&btm, sizeof(BITMAP));
if (ret != sizeof(BITMAP)) return;
// 3. 請求像素數據
m_pRecBMPSocket->Send("D", 30);
int size = btm.bmWidthBytes * btm.bmHeight;
lpData = new char[size];
// 4. 循環接收完整數據
int nBytesRec = 0;
char* pch = lpData;
while (nBytesRec < size) {
int nBytesThisTime = m_pRecBMPSocket->Receive(pch, size - nBytesRec);
if (nBytesThisTime <= 0) break;
nBytesRec += nBytesThisTime;
pch += nBytesThisTime;
}
// 5. 觸發重繪
Invalidate();
}
void CClientView::OnDraw(CDC* pDC) {
if (!lpData) return;
// 構建 BITMAPINFOHEADER
BITMAPINFOHEADER bih = {0};
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = btm.bmWidth;
bih.biHeight = btm.bmHeight;
bih.biPlanes = 1;
bih.biBitCount = btm.bmBitsPixel;
bih.biCompression = BI_RGB;
bih.biSizeImage = btm.bmWidthBytes * btm.bmHeight;
// 創建兼容位圖並設置像素
CBitmap tbitmap;
tbitmap.CreateBitmapIndirect(&btm);
CDC tmemdc;
tmemdc.CreateCompatibleDC(pDC);
SetDIBits(tmemdc.m_hDC, tbitmap, 0, btm.bmHeight, lpData, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
// 拉伸繪製適應視圖大小
CRect trect;
GetClientRect(&trect);
CBitmap* lpOldbit = tmemdc.SelectObject(&tbitmap);
pDC->StretchBlt(0, 0, trect.Width(), trect.Height(),
&tmemdc, 0, 0, btm.bmWidth, btm.bmHeight, SRCCOPY);
tmemdc.SelectObject(lpOldbit);
}
| 環節 | 耗時 | 優化建議 |
|---|---|---|
| 屏幕截取 | ~15-30ms | 使用 DirectX Desktop Duplication API (Win8+) |
| 數據序列化 | ~5-10ms | 改用 JPEG/PNG 壓縮(GDI+/libjpeg-turbo) |
| 網絡傳輸 | 視帶寬而定 | 啟用 TCP_NODELAY、調整發送緩衝區、考慮 UDP+FEC |
| 客戶端解碼繪製 | ~10-20ms | 使用 Direct2D/Direct3D 硬件加速渲染 |
CAsyncSocket 避免阻塞 UI 線程本專案展示了 Windows 平台下基於 GDI + Socket 的遠程桌面基礎實現。雖然核心流程通順,但受限於 GDI 性能與原始位圖傳輸帶寬,實際部署需引入現代圖形 API 與視頻編碼技術。代碼結構清晰,適合作為學習網絡編程、GDI 繪圖、MFC Socket 使用的教學案例。