?? server.c
字號:
//服務器端:發送本機桌面到連接的客戶端
#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"
//默認端口
#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區域結構
struct GdiList GdiStart;
struct GdiList *pGdiNode;
// 這個結構用來在LPARAM參數中傳遞信息到客戶端線程
struct myStruct
{
SOCKET Socket;
HWND hWnd;
};
int SelectProtocols(DWORD dwSetFlags,DWORD dwNotSetFlags,LPWSAPROTOCOL_INFO lpProtocolBuffer,LPDWORD lpdwBufferLength,WSAPROTOCOL_INFO *pProtocol);
//LoadWinsock用來裝載和初始化Winsock,綁定本地地址,創建監聽socket,等候客戶端連接
DWORD WINAPI LoadWinsock(LPVOID lpParam)
{
// 協議變量
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;
// 這個結構用來在LPARAM參數中傳遞信息到客戶端線程
struct myStruct myStructure;
// 為協議的選擇和所有協議的變量決定需要的緩沖區的大小
dwLen = 0;
nRet = WSAEnumProtocols(NULL,NULL,&dwLen);
if (nRet == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAENOBUFS)
return 1;
}
pBuf = malloc(dwLen);
// 為WSASocketGet()得到協議
nRet = SelectProtocols(SETFLAGS,NOTSETFLAGS,(LPWSAPROTOCOL_INFO)pBuf,&dwLen,&Protocol);
// 創建我們的監聽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;
}
// 設置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上將數據發送到緩沖。設置SO_SNDBUF為0,
//從而使winsock直接發送數據到客戶端,而不是將數據緩沖才發送。
nZero = 0;
setsockopt(Listen,SOL_SOCKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));
//開始監聽
listen(Listen,SOMAXCONN);
iAddrSize = sizeof(client);
while (TRUE)
{
// 阻塞方式的接收客戶端的連接,但因為這是一個線程函數,所以用戶不會感到阻塞
Socket = accept(Listen,(struct sockaddr *)&client,&iAddrSize);
if (Socket != INVALID_SOCKET)
{
// 設置傳到客戶端線程的信息的數據結構
myStructure.Socket = Socket;
myStructure.hWnd = hServerWnd;
//找出客戶端的IP地址
memset(szClientIP,'\0',sizeof(szClientIP));
sprintf(szClientIP,"%s",inet_ntoa(client.sin_addr));
// 為每一個客戶端創建一個線程
hThread = CreateThread(NULL,0,ClientThread,(LPVOID)&myStructure,0,&dwThreadId);
if (hThread)
{
//關閉線程句柄
CloseHandle(hThread);
}
}
else
return 1;
}
return 0;
}
//客戶端線程函數,這個函數等候從客戶端程序發送過來的消息,
//如果這個消息是"REFRESH",那么它發送當前的桌面圖片
//如果這個消息是"DISCONNECT",那么它結束和客戶端的連接
//如果這個消息以"WM_"開頭,那么它就根據消息類型,在服務器端執行該消息
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;
// 分析參數
myStructure = (struct myStruct *)lpParam;
MySocket = myStructure->Socket;
hWnd = myStructure->hWnd;
// 設置超時值
timeout.tv_sec = 0; // 秒
timeout.tv_usec = 0; // 微秒
// 設置Socket集合
SocketSet.fd_count = 1;
SocketSet.fd_array[1] = MySocket;
// 輪詢sockets
while(TRUE)
{
// 等候發送過來的數據直到超時
iRet = select(0,&SocketSet,NULL,NULL,&timeout);
if (iRet != 0)
{
//初始化緩沖
memset(szMessage,'\0',sizeof(szMessage));
// 阻塞方式調用recv()
iRecv = recv(MySocket,szMessage,2048,0);
szMessage[iRecv] = '\0';
CHECK_MSG:
// 是不是"REFRESH"消息
if (strncmp(szMessage,"REFRESH",7) == 0)
{
// 捕獲并且發送桌面的更新的區域
iUpdates = SendRegionDisplay(hServerWnd,MySocket);
}
// 檢查從客戶端發送過來的Windows 命令消息,這是一個核心部分
else if (strncmp(szMessage,"WM_",3) == 0)
{
// 解析從客戶端發送過來的消息并發送到本機的消息隊列
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;
}
// 停止查詢,相當于結束該線程
break;
}
}
}
closesocket(MySocket);
return 0;
}
// 解析從客戶端發送過來的消息并發送到本機的消息隊列
void DispatchWMMessage(char *szString)
{
//鼠標消息
struct {char *szWMMouseMsg;}
WMMouseMsg[] = {"WM_MM","WM_LBD","WM_LBU","WM_LBK",
"WM_MBD","WM_MBU","WM_MBK",
"WM_RBD","WM_RBU","WM_RBK"};
// 鍵盤消息
struct {char *szWMKeyBdMsg;}
WMKeyBdMsg[] = {"WM_KD","WM_KU"};
// 通用消息:色彩模式,網格數和壓縮消息
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];
// 分別得到鼠標,鍵盤,通用消息的數目
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命令,截獲命令的參數
iParms = 0;
while (pDest = strchr(szString,';'))
{
iLoc = pDest - szString;
nChar = iLoc;
memset(Command.szElement,'\0',sizeof(Command.szElement));
strncpy(Command.szElement,szString,nChar);
// 發送到命令棧中
pCommandNode = Add_Command(pCommandNode,Command);
memset(szString2,'\0',sizeof(szString2));
strcpy(szString2,&szString[iLoc + 1]);
strcpy(szString,szString2);
iParms++;
if (iParms == 5) // 每條命令5個參數
break;
}
// 處理命令
pCommandNode = CommandStart.pNext;
if (pCommandNode)
{
// 鼠標消息
UINT keyFlags;
int iMessage;
int fWMMouseMsg;
double iScaleX,iScaleY,iX,iY;
DWORD dwX,dwY;
// 鍵盤消息
int fWMKeyBdMsg;
UINT vk;
int fDown;
int cRepeat;
UINT flags;
// 判斷是否有鼠標消息
fWMMouseMsg = FALSE;
for (iLoop = 0;iLoop < nWMMouseMsg;iLoop++)
{
if (strcmp(pCommandNode->Command.szElement,WMMouseMsg[iLoop].szWMMouseMsg) == 0)
{
// 設置鼠標消息的標志
fWMMouseMsg = TRUE;
// 具體的鼠標消息
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;
// 移動到參數棧的下一個節點,x坐標
pCommandNode = pCommandNode->pNext;
iX = atof(pCommandNode->Command.szElement);
// 移動到參數棧的下一個節點,y坐標
pCommandNode = pCommandNode->pNext;
iY = atof(pCommandNode->Command.szElement);
// 移動到參數棧的下一個節點,輔助鍵
pCommandNode = pCommandNode->pNext;
keyFlags = atoi(pCommandNode->Command.szElement);
// 退出循環
break;
}
}
// 如果有鼠標消息則對鼠標消息進行處理
if (fWMMouseMsg)
{
// 得到坐標的范圍因子
iScaleX = 65535.0 / (iWidth - 1);
iScaleY = 65535.0 / (iHeight - 1);
// 對坐標進行比例縮放
iX *= iScaleX;
iY *= iScaleY;
// 轉換成DWORDS
dwX = (DWORD)iX;
dwY = (DWORD)iY;
// 處理鼠標消息
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);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -