服务端开发
1.基础的设计结构
//套接字初始化
WSADATA data;
WSAStartup(MAKEWORD(1, 1), &data);
//TODO:返回值处理
SOCKET serv_sock = socket(PF_INET, SOCK_STREAM, 0); //要求发送的数据可靠可信度高,用TCP
//TODO:校验
sockaddr_in serv_adr;
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = INADDR_ANY; //监听所有IP
serv_adr.sin_port = htons(9527);
//绑定
bind(serv_sock, (sockaddr*)&serv_adr, sizeof(serv_adr));
//TODO:校验
listen(serv_sock, 1);
char buffer[1024] = {0};
recv(serv_sock, buffer, sizeof(buffer), 0);
send(serv_sock, buffer, sizeof(buffer), 0);
closesocket(serv_sock);
WSACleanup();
2.界面隐藏
服务器一般不需要界面的设计,所以需要将界面进行隐藏,界面隐藏的方式有2种,如下所示:
方式一:
1.添加代码的方式进行界面的隐藏
//子系统是窗口的,入口是窗口的入口(这也是标准的窗口应用程序)
#pragma comment(linker,"/subsystem:windows /entry:WinMainCRTStartup")
//子系统是窗口的,入口是命令行
#pragma comment(linker,"/subsystem:windows /entry:mainCRTStartup")
//子系统是控制台的,入口时命令行的(纯后台的没有窗口)
#pragma comment(linker,"/subsystem:console /entry:mainCRTStartup")
//子系统是控制台的,入口是窗口的入口(可以在控制台中开启窗口、消息循环)
#pragma comment(linker,"/subsystem:console /entry:WinMainCRTStartup")
方式二:
2.在编译器中调整属性进行界面隐藏
3.数据包协议的设计
数据包协议的设计为了让数据按照设计进行解析和使用,保障数据安全的同时也能让数据得到更好的封装。
class CPacket
{
public:
CPacket():sHead(0),nLength(0),sCmd(0),sSum(0){}
CPacket(const CPacket& pack) {
sHead = pack.sHead;
nLength = pack.nLength;
sCmd = pack.sCmd;
strData = pack.strData;
sSum = pack.sSum;
}
CPacket(const BYTE* pData, size_t nSize) //解析数据
{
size_t i = 0;
for (; i < nSize; ++i) {
if (*(WORD*)(pData + i) == 0xFEFF) {
sHead = *(WORD*)pData + i;
i += 2; //防止
break;
}
}
if (i + 4 + 2 + 2 > nSize) { //+ length + cmd + sum 包数据可能不全,或者包头未能全部接收到
nSize = 0;
return;
}
nLength = *(DWORD*)(pData + i); i += 4;
if (nLength + i > nSize) { //包未完全接收到,就返回解析失败
nSize = 0;
return;
}
sCmd = *(WORD*)(pData + i); i += 2;
if (nLength <= 4) {
strData.resize(nLength - 2 - 2);
memcpy((void*)strData.c_str(), pData + i, nLength - 4);
i += nLength - 4;
}
sSum = *(WORD*)(pData + i); i += 2;
WORD sum = 0;
for (size_t j = 0; j < strData.size(); j++) {
sum += BYTE(strData[i] & 0xFF);
}
if (sum == sSum) {
nSize = i; //若是包前面用掉部分废数据,需要将i往后移动
return;
}
nSize = 0; //解析失败
}
~CPacket(){}
CPacket& operator=(const CPacket& pack) {
if (this != &pack) {
sHead = pack.sHead;
nLength = pack.nLength;
sCmd = pack.sCmd;
strData = pack.strData;
sSum = pack.sSum;
}
return *this;
}
public:
WORD sHead; //头固定位FE FF
DWORD nLength; //包长度:控制命令开始到和校验结束
WORD sCmd; //控制命令
std::string strData; //包数据
WORD sSum; //和校验
};
在调试时进行数据包内容的查看
//通过Dump来查看包的处理是否有问题
void Dump(BYTE* pData,size_t nSize)
{
std::string strOut;
for (size_t i = 0; i < nSize; i++) {
char buf[8] = "";
if ((i > 0) && (i % 16 == 0)) {
strOut += "\n";
}
snprintf(buf, sizeof(buf), "%02X ", pData[i] & 0xFF); //避免负数
strOut += buf;
}
strOut += "\n";
OutputDebugStringA(strOut.c_str());
}
4.文件操作
1.获取磁盘分区信息
使用这个_chdrive函数进行遍历磁盘的分区操作,以此来获取磁盘的分区情况
void GetDriveInfo(CPacket& recvPack, std::list<CPacket>& sendPacks)
{
DRIVEINFO driveInfo;
for (int i = 1; i <= 26; i++)
{
if (_chdrive(i) == 0)
{
driveInfo.drive[driveInfo.drive_count++] = 'A' + i - 1;
}
}
sendPacks.push_back(CPacket(recvPack.nCmd, (BYTE*)&driveInfo, sizeof(DRIVEINFO)));
}
2.获取文件信息
void GetFileInfo(CPacket& recvPack, std::list<CPacket>& sendPacks)
{
std::string path = recvPack.sData;
if (_chdir(path.c_str()) == 0)
{
FILEINFO fileInfo{};
intptr_t first = _findfirst("*", &fileInfo.data);
if (first == -1)
{
//第一个就没找到:当前这个就是空的
fileInfo.isNull = 1;
sendPacks.push_back(CPacket(recvPack.nCmd, (BYTE*)&fileInfo, sizeof(FILEINFO)));
return;
}
else
{
do
{
//正在发送
fileInfo.isNull = 0;
sendPacks.push_back(CPacket(recvPack.nCmd, (BYTE*)&fileInfo, sizeof(FILEINFO)));
memset(&fileInfo, 0, sizeof(FILEINFO));
} while (_findnext(first, &fileInfo.data) == 0);
//发完了:当前这个就是空的
fileInfo.isNull = 1;
sendPacks.push_back(CPacket(recvPack.nCmd, (BYTE*)&fileInfo, sizeof(FILEINFO)));
}
}
else
{
FILEINFO fileInfo{};
fileInfo.isNull = 1;
sendPacks.push_back(CPacket(recvPack.nCmd, (BYTE*)&fileInfo, sizeof(FILEINFO)));
}
}
3.下载文件
void DownLoadFile(CPacket& recvPack, std::list<CPacket>& sendPacks)
{
static const int buffer_size = 1024 * 10;
static char buffer[buffer_size]{};
std::string path = recvPack.sData;
long long fileLen = 0;
FILE* pFile = fopen(path.c_str(), "rb+");
if (pFile == NULL)
{
//把长度发给控制端,0表示文件为空,或者没有权限
sendPacks.push_back(CPacket(recvPack.nCmd, (BYTE*)&fileLen, 8));
return;
}
//获得文件长度
_fseeki64(pFile, 0, SEEK_END);
fileLen = _ftelli64(pFile);
_fseeki64(pFile, 0, SEEK_SET);
//把长度发给控制端
sendPacks.push_back(CPacket(recvPack.nCmd, (BYTE*)&fileLen, 8));
//读取一点发一点
int readLen = 0;
while ((readLen = fread(buffer, 1, buffer_size, pFile)) > 0)
{
sendPacks.push_back(CPacket(recvPack.nCmd, (BYTE*)buffer, readLen));
memset(buffer, 0, buffer_size);
}
//发完关闭
fclose(pFile);
}
4.文件删除
void DelFile(CPacket& recvPack, std::list<CPacket>& sendPacks)
{
std::string path = recvPack.sData;
WCHAR widePath[MAX_PATH]{};
int transRet = MultiByteToWideChar(CP_ACP, 0, path.c_str(), path.size(), widePath, MAX_PATH);
int success = 0;
if (DeleteFileW(widePath))
{
success = 1;
}
else
{
success = 0;
}
sendPacks.push_back(CPacket(recvPack.nCmd, (BYTE*)&success, sizeof(int)));
}
5.图片观察
远程观察图片
void ScreenWatch(CPacket& recvPack, std::list<CPacket>& sendPacks)
{
CImage screen;
HDC hScreen = ::GetDC(NULL);
int nBitperPixel = GetDeviceCaps(hScreen, BITSPIXEL);
int nWidth = GetDeviceCaps(hScreen, HORZRES);
int nHeight = GetDeviceCaps(hScreen, VERTRES);
screen.Create(nWidth, nHeight, nBitperPixel);
BitBlt(screen.GetDC(), 0, 0, nWidth, nHeight, hScreen, 0, 0, SRCCOPY);
ReleaseDC(NULL, hScreen);
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, 0);
if (hMem == NULL) return;
IStream* pStream = NULL;
HRESULT ret = CreateStreamOnHGlobal(hMem, TRUE, &pStream);
if (ret == S_OK)
{
screen.Save(pStream, Gdiplus::ImageFormatPNG);
LARGE_INTEGER li = { 0 };
pStream->Seek(li, STREAM_SEEK_SET, NULL);
LPVOID pData = GlobalLock(hMem);
sendPacks.push_back(CPacket(recvPack.nCmd, (BYTE*)pData, GlobalSize(hMem), false));
GlobalUnlock(hMem);
}
GlobalFree(hMem);
screen.ReleaseDC();
screen.Destroy();
}
6.鼠标事件的处理
鼠标控制的基本事件的处理
void ControlMouse(CPacket& recvPack, std::list<CPacket>& sendPacks)
{
//控制端发来的鼠标信息
MOUSEINFO mouseInfo;
memcpy(&mouseInfo, recvPack.sData.c_str(), sizeof(MOUSEINFO));
//组成flags
int mouseFlags = 0;
mouseFlags |= mouseInfo.nButton;
mouseFlags |= mouseInfo.nEvent;
if (mouseInfo.nButton != MOUSEBTN::NOTHING)
{
SetCursorPos(mouseInfo.ptXY.x, mouseInfo.ptXY.y);
}
//处理对应事件
switch (mouseFlags)
{
//左键事件处理--------------------------------------------
case MOUSEBTN::LEFT | MOUSEEVE::CLICK: //左键单击
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, GetMessageExtraInfo());
break;
case MOUSEBTN::LEFT | MOUSEEVE::DBCLICK: //左键双击
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, GetMessageExtraInfo());
break;
case MOUSEBTN::LEFT | MOUSEEVE::DOWN: //左键按下
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, GetMessageExtraInfo());
break;
case MOUSEBTN::LEFT | MOUSEEVE::UP: //左键弹起
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, GetMessageExtraInfo());
break;
//中键事件处理--------------------------------------------
case MOUSEBTN::MID | MOUSEEVE::CLICK: //中键单击
mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, GetMessageExtraInfo());
break;
case MOUSEBTN::MID | MOUSEEVE::DBCLICK: //中键双击
mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, GetMessageExtraInfo());
break;
case MOUSEBTN::MID | MOUSEEVE::DOWN: //中键按下
mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, GetMessageExtraInfo());
break;
case MOUSEBTN::MID | MOUSEEVE::UP: //中键弹起
mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, GetMessageExtraInfo());
break;
//右键事件处理--------------------------------------------
case MOUSEBTN::RIGHT | MOUSEEVE::CLICK: //右键单击
mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, GetMessageExtraInfo());
break;
case MOUSEBTN::RIGHT | MOUSEEVE::DBCLICK: //右键双击
mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, GetMessageExtraInfo());
break;
case MOUSEBTN::RIGHT | MOUSEEVE::DOWN: //右键按下
mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, GetMessageExtraInfo());
break;
case MOUSEBTN::RIGHT | MOUSEEVE::UP: //右键弹起
mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, GetMessageExtraInfo());
break;
//移动事件处理--------------------------------------------
case MOUSEBTN::NOTHING | MOUSEEVE::MOVE: //直接移动
SetCursorPos(mouseInfo.ptXY.x, mouseInfo.ptXY.y);
break;
}
//给个回应
sendPacks.push_back(CPacket(recvPack.nCmd));
}
7.锁屏相关操作
void LockMachine(CPacket& recvPack, std::list<CPacket>& sendPacks)
{//锁屏
if (m_hThreadLock == INVALID_HANDLE_VALUE)
{
m_hThreadLock = (HANDLE)_beginthreadex(NULL, 0, &ThreadEntryLock, this, 0, &m_nThreadIdLock);
m_hEventLock = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hEventLock)
{
WaitForSingleObject(m_hEventLock, 100);
}
}
int postRet = PostThreadMessage(m_nThreadIdLock, WM_LOCKMACHINE, NULL, NULL);
if (postRet == 0)
{
Sleep(10);
PostThreadMessage(m_nThreadIdLock, WM_LOCKMACHINE, NULL, NULL);
}
//给个回应
sendPacks.push_back(CPacket(recvPack.nCmd));
}
void UnLockMachine(CPacket& recvPack, std::list<CPacket>& sendPacks)
{//解锁
PostThreadMessage(m_nThreadIdLock, WM_UNLOCKMACHINE, NULL, NULL);
//给个回应
sendPacks.push_back(CPacket(recvPack.nCmd));
}
static unsigned __stdcall ThreadEntryLock(void* arg)
{
CCmdProcessor* thiz = (CCmdProcessor*)arg;
thiz->ThreadLock();
_endthreadex(0);
return 0;
}
void ThreadLock()
{//锁机线程
SetEvent(m_hEventLock);
CLockMachineDlg lockDlg;
lockDlg.Create(IDD_LOCKMACHINEDLG);
::SetWindowPos(lockDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
CRect screenRect(0, 0, screenWidth, (int)(screenHeight * 1.1));
lockDlg.MoveWindow(screenRect);
CRect txtInfoRectOld;
lockDlg.m_txtInfo.GetWindowRect(&txtInfoRectOld);
CRect txtInfoRectNew;
txtInfoRectNew.left = (int)(screenRect.Width() / 2.0 - txtInfoRectOld.Width() / 2);
txtInfoRectNew.top = (int)(screenRect.Height() / 2.0 - txtInfoRectOld.Height() / 2);
txtInfoRectNew.right = txtInfoRectNew.left + txtInfoRectOld.Width();
txtInfoRectNew.bottom = txtInfoRectNew.top + txtInfoRectOld.Height();
lockDlg.m_txtInfo.MoveWindow(txtInfoRectNew);
MSG msg;
while (::GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_LOCKMACHINE)
{
lockDlg.ShowWindow(SW_SHOW);
lockDlg.CenterWindow();
}
if (msg.message == WM_UNLOCKMACHINE)
{
lockDlg.ShowWindow(SW_HIDE);
}
}
}