《遠端控制》-服務端實現(一)

weixin_41798850發表於2021-01-04

設計總覽

目錄

設計總覽

編譯環境

服務端

客戶端

資料包設計

功能設計

IOPC

設計流程

服務端實現(一)

建立服務端專案-Windows桌面嚮導

CServerSocket()

InitSockEnv()

~CServerSocket()

operator =

InitSocket()

AcceptClient()

DealCommand();

Send()

getInStance()特例設計

MakeDriverInfo()

MakeDirectoryInof()

RunFile()

DownloadFile()

MouseEvent()

MouseEvent結構體

SendScreen()

LockMachine()

UnLockMachine()

DeleteLocalFile()

編譯環境

  1. 編譯工具:vs2019
  2. 編譯語言:C/C++
  3. 作業系統:Windows10
  4. 輔助工具:git,StarUML
  5. 網路協議:TCP/IP
  6. 初步設計模式:客戶端-服務端(C/S)模式
  7. 後期設計模式:一對多模式、客戶端mvc架構

服務端

  1. 初始化網路環境 WSAStartup()
  2. 建立服務端套接字 socket()
  3. 初始化服務端資訊 sockaddr_in 結構體
  4. 繫結套接字 bind()
  5. 監聽listen()
  6. 連線accept()
  7. 收發資料 recv send()
  8. 資料處理

客戶端

  1. 初始化網路環境
  2. 建立客戶端套接字socket()
  3. 初始化客戶端網路資訊 sockaddr_in結構體
  4. 連線服務端 connect()
  5. 接收發資料 recv()  send()
  6. 資料處理

資料包設計

  1. 包頭
  2. 命令
  3. 資料長度
  4. 資料
  5. 和校驗

功能設計

  1. 驅動碟符遍歷
  2. 檔案遍歷
  3. 檔案刪除
  4. 檔案下載
  5. 圖傳操作
  6. 滑鼠操作
  7. 鎖屏
  8. 解鎖屏

 

IOPC

完成埠CreateIoCompletionPort

重疊結構OVERLAPPED

非同步連線AccepEx

非同步接收WSARecv

非同步傳送WSASend

 

設計流程

服務端實現(一)

建立服務端專案-Windows桌面嚮導

說明:服務端初步設計,使用Windows桌面嚮導應用應用程式,在設定屬性框裡調成視窗隱藏模式

初步設計完成了網路模組初始化、連線客戶端、接收發資料功能

步驟:

  1. 服務端專案建立
  2. 屬性配置,並且忽略4996錯誤
  1. CServerSocket

說明:該類主要用於網路層通訊,連線客戶端、接收發資料

CServerSocket()

函式原型:CServerSocket();

函式說明:建構函式 用於初始化網路環境,並建立伺服器socket

InitSockEnv()

函式原型:BOOL InitSockEnv();

函式說明:初始化網路環境,採用1.1版本網路庫

返回值:初始化成功返回TRUE,失敗返回FALSE

主要使用的系統函式:WSAStartup()

~CServerSocket()

函式原型:~CServerSocket();

函式說明:解構函式 用於清除網路環境

主要使用的系統函式:WSACleanup()

operator =

函式原型:CClientSocket& operator =(const CClientSocket&);

函式說明:過載複製建構函式,過載操作符號=,用於安全操作,防止錯誤使用“=”號造成嚴重後果。

InitSocket()

函式原型:bool initSocket();

函式說明:初始化服務端資訊,使用TCP/IP協議族,開啟廣播域模式(0.0.0.0),監聽埠為9527,並繫結到服務端socket,開啟監聽。

返回值:布林,成功返回true,失敗返回fasle

主要使用的系統函式:

    • bind()
    • listen()

AcceptClient()

函式原型:bool AcceptClient();

函式說明:連線客戶端,連線客戶端後得到該客戶端socket。

返回值:布林,成功返回true,失敗返回fasle。

主要使用的系統函式:

    • accept()

函式原型:SOCKET accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
函式說明:
//引數1:套接字描述符,該套介面在
listen()後監聽連線
//引數2:由套介面建立時所產生的地址族確定。
//引數3:指向存有addr地址長度的整型數

DealCommand();

函式原型:int DealCommand();

函式說明:接受發資料,解包,取得包裡的命令並返回。
返回值: 成功得到命令 ,  失敗得到 -1。

主要使用的系統函式:

    • recv()
      函式原型:int recv( _In_ SOCKET s, _Out_ char *buf, _In_ int len, _In_ int flags);
      函式說明:接收資料

//引數1:使用接收端的套接字
//引數2:緩衝區,用於接收資料
//引數3:指明緩衝區的長度
//引數4:標誌功能,一般為0

//返回值:若無錯誤發生,recv()返回讀入的位元組數。如果連線已中止,返回0。否則的話,返回SOCKET_ERROR錯誤,使用WSAGetLastError()得到錯誤詳細資訊。

Send()

函式原型:bool Send(const char* pData, int nSize); 
函式說明:傳送資料
//引數1:需要傳送的資料
//引數2:資料大小
//返回值:成功傳送返回true,傳送失敗返回fasle

使用的系統函式:

  • send()
    函式原型:int send(SOCKET s, const char FAR* buf, int len, int flags);
    函式說明:傳送資料
    //引數1:指定傳送端套接字描述符
    //引數2:指明需要傳送的資料緩衝區
    //引數3:該緩衝區的大小
    //引數4:標誌,一般填0

//返回值:若無錯誤發生,send()返回所傳送資料的總數,否則,返回SOCKET_ERROR錯誤,使用WSAGetLastError()得到錯誤詳細資訊。

getInStance()特例設計

為了防止多次外部多次建立伺服器CServerSocket物件從而初始化多次網路環境造成不可預計的後果,採用安全的程式設計方法

  • 將CServerSocket() 建構函式設定為私有成員函式,此時外部無法構造改類
  • 在類的私有內建立一個CHelper類用於初始化唯一的CServerSocket物件,而外部無法訪問CHelper類
  • 宣告一個CHelper類物件為靜態私有成員,並且在cpp中例項化,從而當程式載入初始化時,首先初始化CHelper類,此時呼叫getInstance()即可初始化CServerSocket物件
  • 對外只放出一個靜態函式介面 getInstance(),無法重複建立CServerSocket物件
  • 外部只能通過getInstance()得到唯一一個服務端socket。

 

  1. CPacket資料包類
  1. 資料包設計
  2. 建構函式,初始化
  3. 函式原型:CPacket(WORD nCmd, const BYTE* pData, size_t nSize);

函式說明:資料包封包建構函式,用於把資料封裝成資料包
//引數1:命令
//引數2:資料指標
//引數3:資料大小

  1. 函式原型:CPacket(const BYTE* pData, size_t& nSize);
    函式說明:資料包解包,將包中的資料分配到成員變數中
    //引數1:資料指標
    //引數2:資料大小


  2. 資料包類總覽

 

  1. 功能函式設計

MakeDriverInfo()

函式原型:int MakeDriverInfo();

函式說明:檢視本地磁碟分割槽,並把資訊打包成資料包
//返回值 int 成功返回0,失敗返回 -1
使用主要系統函式:int __cdecl _chdrive(int _Drive) //通過切換26個字母碟符是否能切換成功來判斷碟符存在

MakeDirectoryInof()

函式原型:int MakeDriverInfo();

函式說明:遍歷磁碟檔案,並將得到的資訊打包成資料包。
//返回值:成功返回0,路徑錯誤返回-1,沒有許可權返回-2,空檔案返回-3。
內部使用主要函式

  • int __cdecl _chdir(const char* _Path)
    //函式說明:通過切換到輸入的路徑來判斷是否存在該路徑
    //引數1:路徑
  • int __cdecl _findfirst(const char* _FileName, struct _finddata_t* _FindData)
    //函式說明:獲得當前檔案節點
    //引數1:檔案路徑  填  
    * 表示匹配所有檔案, D:\\*.txt 表示D盤下所有.txt檔案
    //引數2:檔案資訊的結構體 out型
    //返回值:檔案節點
  • int __cdecl _findnext(int _FindHandle, struct _finddata_t* _FindData)
    //函式說明:獲得檔案節點的下一個檔案節點
    //引數1: 當前檔案節點
    //引數2: 下一個檔案的資訊結構體 out型
    //返回值: 下一個檔案節點


通過以上兩個函式配合,從碟符開始,通過do...while() 迴圈可得到遍歷檔案
 

RunFile()

函式原型:int RunFile();

函式功能:執行本地檔案,通過資料包中的路徑,執行檔案
內部使用主要系統函式:
HINSTANCE ShellExecute(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd)
//函式說明:執行指定檔案
//引數1:視窗控制程式碼  這裡填NULL,表示不指定父視窗
//引數2:用於指定進行的操作,當為NULL時,表示預設開啟
//引數3:可執行檔案完整路徑
//引數4:可執行檔案的命令列,這裡設定為NULL
//引數5:指定預設目錄
//引數6:初始化顯示方式,模擬正常開啟檔案使用 SW_SHOWNORMAL
返回值:執行成功會返回應用程式控制程式碼

 

 

DownloadFile()

函式原型:int DownloadFile()

函式說明:下載檔案,獲取資料包中的路徑,使用檔案操作函式讀取檔案到緩衝區,並打包傳送回客戶端。

內部使用的主要系統函式:

  • errno_t fopen_s( FILE** pFile, const char *filename, const char *mode );
    //函式說明:以某種方式開啟指定檔案
    //引數1:檔案指標out型,
    //引數2:檔案路徑
    //引數3:開啟方式,這裡以二進位制讀的方式開啟,為  
    rb
    //返回值:成功返回0,失敗返回錯誤碼
  • int fseek(FILE *stream, long offset, int fromwhere);
    //函式說明:設定檔案指標stream的位置
    //引數1:檔案指標
    //引數2:偏移,這裡填空或者0
    //引數3:將檔案指標指向某個位置,SEEK_SET表示指向檔案頭,SEEK_END表示指向檔案尾
    //返回值: 成功返回0,失敗返回非0值,並設定error的值,可以用perror()函式輸出錯誤。
  • size_t fread(void* buffer,size_t size,size_t count,FILE* stream);
    //函式說明:將檔案指標指向的資料以資料流的方式讀取到目標緩衝區
    //引數1:指定的緩衝區
    //引數2:一次讀取的寬度
    //引數3,讀取的次數
    //引數4:檔案流

//返回值:返回成功讀取的物件個數,若出現錯誤或到達檔案末尾,則可能小於count。
 

 

MouseEvent()

函式原型:int MouseEvent();

函式說明:處理滑鼠操作
//成功返回0,失敗返回-1
內部使用的系統函式:

  • BOOL SetCursorPos(int X,int Y);
    //函式說明:設定滑鼠座標
    //引數1:滑鼠x座標
    //引數2:滑鼠y座標
    //返回值:如果成功,返回非零值;如果失敗,返回值是零,可呼叫GetLastError()得到詳細資訊
  • WIN系統 mouse_event(DWORD dwFlags,DWORD dx,DWORD,dy,DWORD dwData,ULONG_PTR dwExtraInfo);
    //函式說明:滑鼠響應事件
    //引數1:滑鼠動作,如點選、雙擊、左鍵、右鍵等
    //引數2:滑鼠x座標
    //引數3:滑鼠y座標
    //引數4:滑鼠輪滑,正數向前滑,負數向後滑,當dwFlags為輪滑操作時候才設定,一般為0
    //引數5,指定與滑鼠事件相關的值,呼叫GetMessageExtraInfo()來得到
    //返回值:

     

MouseEvent結構體

說明:設計一個滑鼠資訊的資料結構,用於接收客戶端滑鼠操作命令

nButton:0表示左鍵,1表示右鍵,2表示中鍵,4沒有按鍵
nAction: 0表示單擊,1表示雙擊,2表示按下,3表示放開,4不作處理

SendScreen()

函式原型:int SendScreen();

函式說明:遠端桌面,採用圖傳功能實現
內部使用的函式:

  • HDC GetDC(HWND hWnd);
    //功能作用:檢索指定視窗的客戶區的顯示上下文環境控制程式碼
    //引數1:指定視窗控制程式碼
    //返回值:返回值表示指定視窗區域的DC控制程式碼,失敗返回NULL
  • int GetDeviceCaps(HDC hdc,LPRECT lprect);
    //函式功能:獲取DC的指定資料
    //引數1:指定的HDC控制程式碼
    //引數2:指定定資料。BITSPIXEL:畫素相連顏色位數, HORZRES:寬,       VERTRES:高
    //返回值:int資料

LockMachine()

函式原型:int LockMachine();

函式說明:鎖機,通過建立執行緒,讓執行緒建立大於整個螢幕的對話方塊,阻擋滑鼠點選操作,並將滑鼠固定在一個位置,另外做一個訊息迴圈,用於恢復鎖機。暫時未實現鎖定鍵盤操作。

內部使用的函式操作:
鎖定滑鼠功能實現:

  • ShowCursor(BOOL bShow);               //游標操作
  • ::ShowWindow(HWND hWnd, int nCmdShow);  //隱藏或顯示視窗
  • ClipCursor(RECT *lpRect);              //設定滑鼠座標
  • BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)
    //函式說明:從訊息佇列中取資料,本次功能中此處用於解鎖。
    //引數1:訊息結構體指標,用於存放取得的資料
    //引數2:取得訊息的視窗控制程式碼
    //引數3:指定被檢索的最小訊息值的整數,一般用於訊息過濾,為0時,無過濾
    //引數4:指定被檢索的最大訊息值的整數,一般用於訊息過濾,為0時,無過濾
    //返回值

UnLockMachine()

函式原型:int UnLockMachine();

函式功能:解鎖,向鎖機執行緒傳送post訊息


內部使用的系統函式:

  • BOOL PostThreadMessage(DWORD idThread, UINT Msg, WPARAM wParam, LPARAM lParam)
    //功能作用:將訊息傳送到指定執行緒的訊息佇列裡
    //引數1:指定的執行緒id
    //引數2:指定的訊息型別
    //引數3:訊息w,一般是一些常量值
    //引數4:訊息l,一般是傳指標
    //返回值:如果函式呼叫成功,返回非零值。如果函式呼叫失敗,返回值是零。

DeleteLocalFile()

函式原型:int DeleteLocalFile();

函式功能:刪除指定檔案

//返回值:成功返回0,失敗返回非0值
內部使用的函式:

  • BOOL DeleteFile(LPCWSTR lpFileName)

//功能作用:刪除指定檔案,測試刪除為永久刪除,不放入回收站,需要呼叫者的許可權足夠
//引數1:指定檔案路徑的指標
//返回值:成功返回0,失敗返回非0值

相關文章