怎么接收到命令,以及如何将结果返回给客户端在2、3、4节已经介绍清楚,本节只讨论功能实现
1 运行文件
逻辑步骤:
-
获取运行的文件的路径
-
调用ShellExecuteA运行文件
参考代码:
int RunFile() { // 拿到路径 std::string strFilePath; CServerSocket::getInstance()->GetFilePath(strFilePath); // ShellExecuteA 选用A是因为std::string 是多字节字符集的 // 对指定文件执行操作。 BYTE result = TRUE; // 执行文件失败 if ((INT_PTR)ShellExecuteA(NULL, NULL, strFilePath.c_str(), NULL, NULL, SW_SHOWNORMAL) < 32) { result = FALSE; CPacket packet(2, &result, 1); CServerSocket::getInstance()->Send(packet); return -1; } // 执行完后返回一个数据包表示当前命令服务器接收并执行了 CPacket packet(2, &result, 1); CServerSocket::getInstance()->Send(packet); return 0; }
2 下载文件
下载文件的本质就是对方发送一个下载文件的路径(第五节回去文件和目录信息),我们拿到这个路径,对这个文件进行读取,我们可以先获取文件有多少字节,发送给客户端,让客户端那边有个进度,后面一次读取多少就发送给客户端,客户端发送命令后就等待接收数据。
逻辑步骤:
-
获取文件路径
-
获取文件长度
-
不停的read,每read一次就发送一次read到的数据
参考代码:
int DownloadFile() { // 获取要下载的文件路径 std::string strFilePath; CServerSocket::getInstance()->GetFilePath(strFilePath); // 因为不知道对方要下载什么类型的文件所有以二进制的方式读取 // 打开文件 // 文件长度 long long data = 0; FILE* pfile = fopen(strFilePath.c_str(), "rb"); if (pfile == NULL) { CPacket packet(4, (BYTE*)&data, 8); CServerSocket::getInstance()->Send(packet); return -1; } // 获取文件长度 // fseek 和 _fseeki64 函数将与 stream 关联的文件指针(如有)一起移动到新位置 // SEEK_END:fseek将文件指针移到指定位置。SEEK_END 文件结尾 // 0:SEEK_END 中的第几个字节 fseek(pfile, 0, SEEK_END); // ftell 和 _ftelli64 函数检索与 stream 关联的文件指针(如果有)的当前位置。 位置表示为相对于流开头的偏移量。 data = ftell(pfile); // 恢复文件指针在初始值 fseek(pfile, 0, SEEK_SET); CPacket head(4, (BYTE*)&data, 8); CServerSocket::getInstance()->Send(head); // 读取发送文件数据 char buffer[1024] = ""; size_t rlen = 0; /* fread 函数最多从输入 stream 中读取 size 字节的 count 项并将它们存储在 buffer 中。 与 stream 关联的文件指针(如有)以 fread 读取的字节数推进。 */ do { // fread一次读1字节 一次总共最大读1024字节 rlen = fread(buffer, 1, 1024, pfile); CPacket pack(4, (BYTE*)buffer, rlen); CServerSocket::getInstance()->Send(pack); } while (rlen > 0); // 关闭文件 fclose(pfile); // 读取结束发一个空包,好给客户端一个结束接收的标志 CPacket pack(4, NULL, 0); CServerSocket::getInstance()->Send(pack); return 0; }