本帖最后由 碧天澈水 于 2020-3-3 16:19 编辑
疫情期间,学习了Windows的sokcet,做了一个简单的远控程序,分享给大家,共同学习
本程序用的TCP协议,没有上任何模型,只支持一对一,不允许多客户端连接。
以下是运行的截图:
在运行期间,可能上传和下载文件由问题(偶尔会出现问题,目前还没调试好)
代码:
控制端与被控端都是分2此接收消息,先接收消息头,确定消息的类型和长度,在根据长度接收确定的消息数据
以下是定义的消息头以及消息类型
[Asm] 纯文本查看 复制代码 enum ControlProtocol
{
CP_HEART, //心跳包
CP_SCREENDATA, //屏幕数据
CP_SCREENQUIT, //屏幕退出
CP_DRIVE, //获取驱动器
CP_NEXTFOLDER, //获取下一层文件夹内容
CP_PREVFOLDER, //获取上一层文件夹内容
CP_HAVENEXTFOLDER, //有下一层文件夹
CP_NONEXTFOLDER, //没有下一层文件夹
CP_HAVEPREVFOLDER, //有上一层文件夹
CP_NOPREVFOLDER, //没有上一层文件夹
CP_FILEDOWNLOAD, //文件下载
CP_ISFILEFOLDER, //是文件夹
CP_ISFILE, //是文件
CP_BEGINFILEDOWN, //开始文件下载
CP_FILESIZE, //文件大小
CP_FILEDATA, //文件数据
CP_DOWNFILEDATAEND, //下载文件数据结束
CP_FILENEXTDATA, //文件下一条数据
CP_FILEUPLOAD, //上传文件
CP_STARTCMD, //启动CMD
CP_CMDDATA, //CMD数据
CP_CMDORDER, //CMD命令
CP_CMDQUIT, //CMD退出
CP_PROCESSINFO, //进程信息
CP_REFRESHPROCESS, //刷新进程信息
CP_TERMINATEPROCESS, //结束进程消息
CP_PROCESSSUCCEND, //结束进程成功
CP_PROCESSFAILED //结束进程失败
};
//协议头信息
typedef struct _HEAD_INFO
{
_HEAD_INFO()
{
m_Cmd = -1;
m_Len = 0;
}
int m_Cmd; //命令
int m_Len; //长度
}HEAD_INFO, *P_HEAD_INFO;
//屏幕分辨率及压缩后大小
typedef struct _SCREEN_INFO
{
_SCREEN_INFO()
{
m_Width = 0;
m_Height = 0;
m_SrcSize = 0;
m_CompressedSize = 0;
}
int m_Width; //屏幕宽度
int m_Height; //屏幕高度
unsigned long m_SrcSize; //原先的大小
unsigned long m_CompressedSize; //压缩后大小
}SCREEN_INFO, *P_SCREEN_INFO;
接收到消息后,通过发消息的方式,将各种消息投递到处理该消息的窗口
[Asm] 纯文本查看 复制代码 //窗口收发数据线程
DWORD WINAPI CProcessMessage::RecvSendThread(LPVOID lpParameter)
{
CProcessMessage *pThis = (CProcessMessage *)lpParameter;
while (true)
{
HEAD_INFO head;
//接收头数据
pThis->m_SockTcp.Recv(pThis->m_ClinetSokc, (char *)&head, sizeof(head));
//匹配数据
pThis->Matching(head);
}
return TRUE;
}
[Asm] 纯文本查看 复制代码 void CProcessMessage::Matching(HEAD_INFO head)
{
switch (head.m_Cmd)
{
case CP_HEART://心跳包
{
m_HeartTime = clock();
break;
}
case CP_SCREENDATA://屏幕数据
{
MatchingScreenData();
//SendScreenData(); //获取下一个屏幕信息
break;
}
case CP_DRIVE://驱动器
{
MatchingDrive(head);
break;
}
case CP_NEXTFOLDER://下一层文件夹
{
MatchingNextFolder(head);
break;
}
case CP_PREVFOLDER://上一层文件夹
{
MatchingPrevFolder(head);
break;
}
case CP_HAVENEXTFOLDER://有下一层文件夹
{
MatchingHaveNextFolder();
break;
}
case CP_NONEXTFOLDER://没有下一层文件夹
{
break;
}
case CP_HAVEPREVFOLDER://有上一层文件
{
MatchingHavePrevFolder();
break;
}
case CP_NOPREVFOLDER://没有上一层文件
{
break;
}
case CP_ISFILEFOLDER://是文件夹
{
MatchingIsFloder();
break;
}
case CP_ISFILE://是文件
{
MatchingIsFile();
break;
}
case CP_FILESIZE://文件大小
{
MatchingFileSize();
break;
}
case CP_FILEDATA://文件数据
{
MatchingFileData(head);
break;
}
case CP_FILENEXTDATA:
{
MatchingFileNextData();
break;
}
case CP_DOWNFILEDATAEND://文件结束
{
MatchingFileOver();
break;
}
case CP_CMDDATA://CMD数据
{
MatchingCmdData(head);
break;
}
case CP_PROCESSINFO://进程信息
{
MatchingProcessInfo(head);
break;
}
case CP_REFRESHPROCESS://刷新进程信息
{
MatchingRefreshProcessInfo();
break;
}
case CP_PROCESSSUCCEND://结束进程成功
{
MatchingProcessSucceed();
break;
}
case CP_PROCESSFAILED://结束进程失败
{
MatchingProcessFailure();
break;
}
}
}
下面是匹配到数据,投递到相应的消息窗口(这里只举例一个,其他都差不多)
[Asm] 纯文本查看 复制代码 //屏幕数据
void CProcessMessage::MatchingScreenData()
{
P_SCREEN_INFO pScreenInfo = new SCREEN_INFO();
//接收屏幕相关信息
int nRet = m_SockTcp.Recv(m_ClinetSokc, (char*)pScreenInfo, sizeof(SCREEN_INFO));
if (nRet <= 0)
{
::PostMessage(m_hWnd, WM_RECVDATAERROR, NULL, NULL);
return;
}
char *pScreenData = new char[pScreenInfo->m_CompressedSize];
ZeroMemory(pScreenData, pScreenInfo->m_CompressedSize);
//接收屏幕数据
int nTotal = pScreenInfo->m_CompressedSize;
int nCurSize = 0;
while (nCurSize != nTotal)
{
int nRetByte = m_SockTcp.Recv(m_ClinetSokc, pScreenData + nCurSize, nTotal - nCurSize);
if (nRetByte <= 0)
{
::PostMessage(m_hWnd, WM_RECVDATAERROR, NULL, NULL);
return;
}
nCurSize += nRetByte;
}
::PostMessage(m_hWnd, WM_SCREENDATA, (WPARAM)pScreenInfo, (LPARAM)pScreenData);
}
大概就是这样了,以上是控制端的部分代码,被控端其实与控制端大同小异,都是先接收消息头,在接收命令,根据命令执行代码,然后返回
编译环境是VS2015,因为是动态库编译,如果不能运行,有VS编译器的重新编译即可,没有编译器的可以下载VS2015的运行库,即可运行
本程序仅应用于学习,交流
最后:有哪位大神可以教我一下在本论坛发帖的排版呢,不会排版。看人家发帖的排版羡慕之极
链接:https://pan.baidu.com/s/116h113a8TwoTYuNFpWXE9g 提取码:tcxs |