?? server.c
字號(hào):
//服務(wù)器端:發(fā)送本機(jī)桌面到連接的客戶端
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <winuser.h>
#include "Server.h"
#include "Command.h"
#include "Gdi.h"
#include "HuffCompress.h"
#include "RLE.h"
//默認(rèn)端口
#define DEFAULT_PORT 5150
#define SETFLAGS XP1_GUARANTEED_DELIVERY|XP1_GUARANTEED_ORDER
#define NOTSETFLAGS XP1_CONNECTIONLESS
#define LPBMIH LPBITMAPINFOHEADER
UINT gPort = DEFAULT_PORT;
int nGridX = 8;
int nGridY = 2;
DWORD dwLen,dwCompress,dwSendLen;
int iCompressionLevel = 10;
HWND hServerWnd;
HDC hDDC = NULL,hMemDC,hNullDC;
BOOL fChange = FALSE;
SOCKET Socket;
SOCKET Listen;
int iWidth,iHeight;
WORD bmBitsPixel = 4;
// 指向全局位圖
BOOL fDIBitmap = FALSE;
// GDI區(qū)域結(jié)構(gòu)
struct GdiList GdiStart;
struct GdiList *pGdiNode;
// 這個(gè)結(jié)構(gòu)用來(lái)在LPARAM參數(shù)中傳遞信息到客戶端線程
struct myStruct
{
SOCKET Socket;
HWND hWnd;
};
int SelectProtocols(DWORD dwSetFlags,DWORD dwNotSetFlags,LPWSAPROTOCOL_INFO lpProtocolBuffer,LPDWORD lpdwBufferLength,WSAPROTOCOL_INFO *pProtocol);
//LoadWinsock用來(lái)裝載和初始化Winsock,綁定本地地址,創(chuàng)建監(jiān)聽(tīng)socket,等候客戶端連接
DWORD WINAPI LoadWinsock(LPVOID lpParam)
{
// 協(xié)議變量
LPBYTE pBuf;
WSAPROTOCOL_INFO Protocol;
int nRet;
int nZero = 0;
int iAddrSize;
HANDLE hThread;
DWORD dwThreadId;
char szClientIP[81];
char szString[255];
struct sockaddr_in local,client;
// 這個(gè)結(jié)構(gòu)用來(lái)在LPARAM參數(shù)中傳遞信息到客戶端線程
struct myStruct myStructure;
// 為協(xié)議的選擇和所有協(xié)議的變量決定需要的緩沖區(qū)的大小
dwLen = 0;
nRet = WSAEnumProtocols(NULL,NULL,&dwLen);
if (nRet == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAENOBUFS)
return 1;
}
pBuf = malloc(dwLen);
// 為WSASocketGet()得到協(xié)議
nRet = SelectProtocols(SETFLAGS,NOTSETFLAGS,(LPWSAPROTOCOL_INFO)pBuf,&dwLen,&Protocol);
// 創(chuàng)建我們的監(jiān)聽(tīng)socket
Listen = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_IP,NULL,0,SOCK_STREAM);
if (Listen == SOCKET_ERROR)
{
sprintf(szString,"socket() failed: %d",WSAGetLastError());
MessageBox(NULL,szString,"Remote Server",MB_OK);
return 1;
}
// 設(shè)置server端信息
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(gPort);
// 綁定到socket
if (bind(Listen,(struct sockaddr *)&local,sizeof(local)) == SOCKET_ERROR)
{
sprintf(szString,"bind() failed: %d\n", WSAGetLastError());
MessageBox(NULL,szString,"Remote Server",MB_OK);
return 1;
}
//為了減小CPU的利用率,禁止在socket上將數(shù)據(jù)發(fā)送到緩沖。設(shè)置SO_SNDBUF為0,
//從而使winsock直接發(fā)送數(shù)據(jù)到客戶端,而不是將數(shù)據(jù)緩沖才發(fā)送。
nZero = 0;
setsockopt(Listen,SOL_SOCKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));
//開(kāi)始監(jiān)聽(tīng)
listen(Listen,SOMAXCONN);
iAddrSize = sizeof(client);
while (TRUE)
{
// 阻塞方式的接收客戶端的連接,但因?yàn)檫@是一個(gè)線程函數(shù),所以用戶不會(huì)感到阻塞
Socket = accept(Listen,(struct sockaddr *)&client,&iAddrSize);
if (Socket != INVALID_SOCKET)
{
// 設(shè)置傳到客戶端線程的信息的數(shù)據(jù)結(jié)構(gòu)
myStructure.Socket = Socket;
myStructure.hWnd = hServerWnd;
//找出客戶端的IP地址
memset(szClientIP,'\0',sizeof(szClientIP));
sprintf(szClientIP,"%s",inet_ntoa(client.sin_addr));
// 為每一個(gè)客戶端創(chuàng)建一個(gè)線程
hThread = CreateThread(NULL,0,ClientThread,(LPVOID)&myStructure,0,&dwThreadId);
if (hThread)
{
//關(guān)閉線程句柄
CloseHandle(hThread);
}
}
else
return 1;
}
return 0;
}
//客戶端線程函數(shù),這個(gè)函數(shù)等候從客戶端程序發(fā)送過(guò)來(lái)的消息,
//如果這個(gè)消息是"REFRESH",那么它發(fā)送當(dāng)前的桌面圖片
//如果這個(gè)消息是"DISCONNECT",那么它結(jié)束和客戶端的連接
//如果這個(gè)消息以"WM_"開(kāi)頭,那么它就根據(jù)消息類型,在服務(wù)器端執(zhí)行該消息
DWORD WINAPI ClientThread(LPVOID lpParam)
{
HWND hWnd;
SOCKET MySocket;
FD_SET SocketSet;
struct timeval timeout;
char szMessage[2049];
DWORD iRecv;
struct myStruct *myStructure;
DWORD iLength;
DWORD iRet;
int iUpdates;
// 分析參數(shù)
myStructure = (struct myStruct *)lpParam;
MySocket = myStructure->Socket;
hWnd = myStructure->hWnd;
// 設(shè)置超時(shí)值
timeout.tv_sec = 0; // 秒
timeout.tv_usec = 0; // 微秒
// 設(shè)置Socket集合
SocketSet.fd_count = 1;
SocketSet.fd_array[1] = MySocket;
// 輪詢sockets
while(TRUE)
{
// 等候發(fā)送過(guò)來(lái)的數(shù)據(jù)直到超時(shí)
iRet = select(0,&SocketSet,NULL,NULL,&timeout);
if (iRet != 0)
{
//初始化緩沖
memset(szMessage,'\0',sizeof(szMessage));
// 阻塞方式調(diào)用recv()
iRecv = recv(MySocket,szMessage,2048,0);
szMessage[iRecv] = '\0';
CHECK_MSG:
// 是不是"REFRESH"消息
if (strncmp(szMessage,"REFRESH",7) == 0)
{
// 捕獲并且發(fā)送桌面的更新的區(qū)域
iUpdates = SendRegionDisplay(hServerWnd,MySocket);
}
// 檢查從客戶端發(fā)送過(guò)來(lái)的Windows 命令消息,這是一個(gè)核心部分
else if (strncmp(szMessage,"WM_",3) == 0)
{
// 解析從客戶端發(fā)送過(guò)來(lái)的消息并發(fā)送到本機(jī)的消息隊(duì)列
DispatchWMMessage(szMessage);
// 看看是否還有消息
iLength = strlen(szMessage);
if (iLength > 0)
goto CHECK_MSG;
}
// 檢查是否是查詢消息
else if (strncmp(szMessage,"RESOLUTION",10) == 0)
{
SendResolution(MySocket);
}
// 檢查是否是DISCONNECT消息
else if (strncmp(szMessage,"DISCONNECT",10) == 0)
{
fChange = FALSE;
fDIBitmap = FALSE;
pGdiNode = GdiStart.pNext;
while (pGdiNode)
{
free(pGdiNode->Gdi.pDIBitmap);
free(pGdiNode->Gdi.pDIBChangeStart);
pGdiNode->Gdi.fDIBitmap = FALSE;
pGdiNode->Gdi.fChange = FALSE;
pGdiNode = pGdiNode->pNext;
}
// 停止查詢,相當(dāng)于結(jié)束該線程
break;
}
}
}
closesocket(MySocket);
return 0;
}
// 解析從客戶端發(fā)送過(guò)來(lái)的消息并發(fā)送到本機(jī)的消息隊(duì)列
void DispatchWMMessage(char *szString)
{
//鼠標(biāo)消息
struct {char *szWMMouseMsg;}
WMMouseMsg[] = {"WM_MM","WM_LBD","WM_LBU","WM_LBK",
"WM_MBD","WM_MBU","WM_MBK",
"WM_RBD","WM_RBU","WM_RBK"};
// 鍵盤(pán)消息
struct {char *szWMKeyBdMsg;}
WMKeyBdMsg[] = {"WM_KD","WM_KU"};
// 通用消息:色彩模式,網(wǎng)格數(shù)和壓縮消息
struct {char *szMsg;}
Msg[] = {"WM_COMP","WM_GRID","WM_CMOD"};
int nWMMouseMsg;
int nWMKeyBdMsg;
int nMsg;
struct CommandList CommandStart;
struct CommandList *pCommandNode;
struct CommandDS Command;
char *pDest;
int iLoc,nChar;
int iLoop,iParms;
char szString2[2049];
// 分別得到鼠標(biāo),鍵盤(pán),通用消息的數(shù)目
nWMMouseMsg = (int)(sizeof(WMMouseMsg)/sizeof(WMMouseMsg[0]));
nWMKeyBdMsg = (int)(sizeof(WMKeyBdMsg)/sizeof(WMKeyBdMsg[0]));
nMsg = (int)(sizeof(Msg)/sizeof(Msg[0]));
// 初始化command鏈表
CommandStart.pNext = NULL;
pCommandNode = &CommandStart;
// 分析command命令,截獲命令的參數(shù)
iParms = 0;
while (pDest = strchr(szString,';'))
{
iLoc = pDest - szString;
nChar = iLoc;
memset(Command.szElement,'\0',sizeof(Command.szElement));
strncpy(Command.szElement,szString,nChar);
// 發(fā)送到命令棧中
pCommandNode = Add_Command(pCommandNode,Command);
memset(szString2,'\0',sizeof(szString2));
strcpy(szString2,&szString[iLoc + 1]);
strcpy(szString,szString2);
iParms++;
if (iParms == 5) // 每條命令5個(gè)參數(shù)
break;
}
// 處理命令
pCommandNode = CommandStart.pNext;
if (pCommandNode)
{
// 鼠標(biāo)消息
UINT keyFlags;
int iMessage;
int fWMMouseMsg;
double iScaleX,iScaleY,iX,iY;
DWORD dwX,dwY;
// 鍵盤(pán)消息
int fWMKeyBdMsg;
UINT vk;
int fDown;
int cRepeat;
UINT flags;
// 判斷是否有鼠標(biāo)消息
fWMMouseMsg = FALSE;
for (iLoop = 0;iLoop < nWMMouseMsg;iLoop++)
{
if (strcmp(pCommandNode->Command.szElement,WMMouseMsg[iLoop].szWMMouseMsg) == 0)
{
// 設(shè)置鼠標(biāo)消息的標(biāo)志
fWMMouseMsg = TRUE;
// 具體的鼠標(biāo)消息
if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_MM\0") == 0)
iMessage = 1;
else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_LBD\0") == 0)
iMessage = 2;
else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_LBU\0") == 0)
iMessage = 3;
else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_LBK\0") == 0)
iMessage = 4;
else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_MBD\0") == 0)
iMessage = 5;
else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_MBU\0") == 0)
iMessage = 6;
else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_MBK\0") == 0)
iMessage = 7;
else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_RBD\0") == 0)
iMessage = 8;
else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_RBU\0") == 0)
iMessage = 9;
else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_RBK\0") == 0)
iMessage = 10;
// 移動(dòng)到參數(shù)棧的下一個(gè)節(jié)點(diǎn),x坐標(biāo)
pCommandNode = pCommandNode->pNext;
iX = atof(pCommandNode->Command.szElement);
// 移動(dòng)到參數(shù)棧的下一個(gè)節(jié)點(diǎn),y坐標(biāo)
pCommandNode = pCommandNode->pNext;
iY = atof(pCommandNode->Command.szElement);
// 移動(dòng)到參數(shù)棧的下一個(gè)節(jié)點(diǎn),輔助鍵
pCommandNode = pCommandNode->pNext;
keyFlags = atoi(pCommandNode->Command.szElement);
// 退出循環(huán)
break;
}
}
// 如果有鼠標(biāo)消息則對(duì)鼠標(biāo)消息進(jìn)行處理
if (fWMMouseMsg)
{
// 得到坐標(biāo)的范圍因子
iScaleX = 65535.0 / (iWidth - 1);
iScaleY = 65535.0 / (iHeight - 1);
// 對(duì)坐標(biāo)進(jìn)行比例縮放
iX *= iScaleX;
iY *= iScaleY;
// 轉(zhuǎn)換成DWORDS
dwX = (DWORD)iX;
dwY = (DWORD)iY;
// 處理鼠標(biāo)消息
if (iMessage == 1)
{
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE,dwX,dwY,0,0);
}
else if (iMessage == 2)
{
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTDOWN,dwX,dwY,0,0);
}
else if (iMessage == 3)
{
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTUP,dwX,dwY,0,0);
}
else if (iMessage == 4)
{
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTDOWN,dwX,dwY,0,0);
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTUP,dwX,dwY,0,0);
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTDOWN,dwX,dwY,0,0);
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTUP,dwX,dwY,0,0);
}
else if (iMessage == 5)
{
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEDOWN,dwX,dwY,0,0);
}
else if (iMessage == 6)
{
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEUP,dwX,dwY,0,0);
}
else if (iMessage == 7)
{
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEDOWN,dwX,dwY,0,0);
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -