文件监控之查找/删除/下载/上传
这两节主要实现四个功能:文件查找,删除,下载,上传。
这节主要做客户端:
FileSpy类:
1.首先创建一个FileSpy类。
2.遍历目录/文件夹函数:
std::vector<std::string> FileSpy::getDirs(std::string dir)
{
WIN32_FIND_DATAA findData;
HANDLE hFind = FindFirstFileA(dir.append("\\*").data(), &findData);
std::vector<std::string> files;
if (hFind == INVALID_HANDLE_VALUE) {
return files;
}
// 遍历目录来获取路径
while (FindNextFileA(hFind, &findData)) {
// 不需要后退和当前目录
if(!strcmp(findData.cFileName,"..") || !strcmp(findData.cFileName,".")) {
continue;
}
// 判断路径
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
files.push_back(findData.cFileName);
}
}
// 释放句柄
CloseHandle(hFind);
return files;
}
std::vector<std::string> FileSpy::getFiles(std::string dir)
{
WIN32_FIND_DATAA findData;
HANDLE hFind = FindFirstFileA(dir.append("\\*").data(), &findData);
std::vector<std::string> files;
if (hFind == INVALID_HANDLE_VALUE) {
return files;
}
// 遍历目录来获取文件
while (FindNextFileA(hFind, &findData)) {
// 不需要后退和当前目录
if(!strcmp(findData.cFileName,"..") || !strcmp(findData.cFileName,".")) {
continue;
}
// 判断不是路径
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
files.push_back(findData.cFileName);
}
}
// 释放句柄
CloseHandle(hFind);
return files;
}
3.查找所有盘符,比如:C盘,D盘:
std::vector<std::string> FileSpy::getDrives()
{
std::vector<std::string> drives;
// 遍历a-z盘符
for (int i='b'; i<='z'; i++) {
char d[MAX_PATH];
sprintf(d, "%c:\\*", i);
WIN32_FIND_DATAA findData;
HANDLE h = FindFirstFileA(d, &findData);
if (h != INVALID_HANDLE_VALUE) {
d[strlen(d)-1] = '\0';
drives.push_back(d);
// 释放句柄
CloseHandle(h);
}
}
return drives;
}
4.至于网络方面都和上一节没什么区别。
代码修改:
1.更改TcpSocket类sendData函数:
bool TcpSocket::sendData(const char *data,unsigned int size)
{
if ((int)mSock == SOCKET_ERROR) {
std::cout << "Socket do not allowed to send data without connected " << std::endl;
std::fflush(stdout);;
return false;
}
int ret = SOCKET_ERROR;
const unsigned int packetLen = 800;
// 小于pakcetLen的话,就直接发送,不然就分包发送
if (size <= packetLen) {
ret = send(mSock, data, size, 0);
// 出现错误,断开连接
if (ret == SOCKET_ERROR) {
std::cout << "Failed to send data to " << mIp << std::endl;
std::fflush(stdout);;
dissconnect();
}
} else {
unsigned int pos = 0;
while (pos < size) {
unsigned int sendSize = pos+packetLen > size ? size-pos : packetLen;
// 发送
ret = send(mSock, data+pos, sendSize, 0);
// 出现错误,断开连接
if (ret == SOCKET_ERROR) {
std::cout << "Failed to send data to " << mIp << std::endl;
std::fflush(stdout);;
dissconnect();
break;
}
pos += packetLen;
}
}
return ret != SOCKET_ERROR ? true : false;
}
我上代码了:
FileSpy.h
/*
*
* Author: sumkee911@gmail.com
* Date: 23-12-2016
* Brief: 实现查找,删除,下载,上传功能
*
*/
#ifndef FILESPY_H
#define FILESPY_H
#include "tcpsocket.h"
#include <windows.h>
#include <iostream>
#include <map>
#include <vector>
class FileSpy
{
public:
FileSpy();
// 服务端向客户端发送的指令(你觉得有需要你也可以增加自己的指令)
const std::string CmdGetDirFiles = "GET_DIRS_FILES"; // 获取路径下的所有文件名和路径名
const std::string CmdDownloadFile = "DOWNLOAD_FILE"; // 服务端从客户也下载文件
const std::string CmdUploadFile = "UPLOAD_FILE"; // 服务端上传文件到客户端
const std::string CmdDeleteFile = "DELETE_FILE"; // 服务端在客户端删除文件
// 客户端向服务端发送的指令(你觉得有需要你也可以增加自己的指令)
const std::string CmdSendDrives = "SEND_DRIVES"; // 发送盘符
const std::string CmdSendDirs = "SEND_DIRS"; // 发送路径下的所有路径名
const std::string CmdSendFiles = "SEND_FILES"; // 发送路径下的所有文件名
const std::string CmdDeleteFileSuccess = "DELETE_SUCCESS"; // 成功删除文件
const std::string CmdDeleteFileFailed = "DELETE_FAILED"; // 删除文件失败
// 分割符号和结束符号,比如获取文件夹所有文件命令:FILES<分割符>FILEA<文件分割符>FILEB<文件分割符>FILEC<结束符号>
const std::string CmdSplit = ";";
const std::string CmdEnd = "\r\n";
const std::string CmdFileSplit = "|";
// 这个类的入口函数
static void startByNewThread(std::string domain, int port);
static DWORD WINAPI fileSpyThreadProc(LPVOID args);
static void startFileSpy(std::string domain, int port);
// 命令解析函数
static void addDataToBuffer(TcpSocket *sock, std::string &buf, char *data, int size);
static std::map<std::string, std::string> parseArgs(std::string &data);
static void processCmd(TcpSocket *sock, std::string &cmd, std::string &data);
// 命令处理函数
static void doGetDirFiles(TcpSocket *sock, std::map<std::string, std::string> &args);
static void doDownloadFile(TcpSocket *sock, std::map<std::string, std::string> &args);
static void doUploadFile(TcpSocket *sock, std::map<std::string, std::string> &args);
static void doDeleteFile(TcpSocket *sock, std::map<std::string, std::string> &args);
// 获取所有盘符
static std::vector<std::string> getDrives();
// 获取路径下的所有路径
static std::vector<std::string> getDirs(std::string dir);
// 获取路径下的所有文件
static std::vector<std::string> getFiles(std::string dir);
// 发送文件数据包头
typedef struct {
char fileName[256];
unsigned int len;
} FileHeader;
// 发送文件入口函数
static void startSendFileByNewThread(std::string filePath, std::string domain, int port);
static DWORD WINAPI sendFileThreadProc(LPVOID args);
static void startSendFile(std::string filePath, std::string domain, int port);
// 接收文件入口函数
static void startRecvFileByNewThread(std::string filePath, std::string domain, int port);
static DWORD WINAPI recvFileThreadProc(LPVOID args);
static void startRecvFile(std::string filePath, std::string domain, int port);
};
#endif // FILESPY_H
filespy.cpp
#include "filespy.h"
// 初始化FileSpy
static FileSpy gSpy;
FileSpy::FileSpy()
{
}
void FileSpy::startByNewThread(std::string domain, int port)
{
// 将域名和端口数据转换成一个字符指针类型
char *args = new char[MAX_PATH+sizeof(int)];
domain.reserve(MAX_PATH);
memcpy(args,domain.data(), MAX_PATH);
memcpy(args+MAX_PATH,(char*)&port, sizeof(int));
// 创建新线程
HANDLE h = CreateThread(NULL,0, FileSpy::fileSpyThreadProc,(LPVOID)args,0,NULL);
if (!h) {
std::cout << "Failed to create new thread" << std::endl;
std::fflush(stdout);
}
}
DWORD FileSpy::fileSpyThreadProc(LPVOID args)
{
char domain[MAX_PATH];
memcpy(domain, args, MAX_PATH);
int port = *((int*)((char*)args+MAX_PATH));
// 开始监控
startFileSpy(domain, port);
// 释放参数
delete (char *)args;
return true;
}
void FileSpy::startFileSpy(std::string domain, int port)
{
// 连接到服务器,接收服务器的指令
TcpSocket sock;
if (!sock.connectTo(domain, port)) {
std::cout << "Failed to connect server for file spy" << std::endl;
std::fflush(stdout);
}
// 死循环,不断从服务端接收数据
const int packetSize = 800;
char szData[packetSize];
int ret;
std::string buf;
while (1) {
ret = sock.recvData(szData, packetSize);
// 出现错误
if (ret == SOCKET_ERROR || ret == 0) {
break;
}
// 把数据加入到缓冲区
addDataToBuffer(&sock, buf, szData, ret);
}
}
void FileSpy::addDataToBuffer(TcpSocket *sock, std::string &buf, char *data, int size)
{
buf.append(data,size);
// 把数据转换成指令模式
int endIndex;
while ((endIndex = buf.find(gSpy.CmdEnd)) >= 0) {
std::string line = buf.substr(0,endIndex);
buf.erase(0, endIndex+gSpy.CmdEnd.length());
// 获取指令
int firstSplit = line.find(gSpy.CmdSplit);
std::string cmd = line.substr(0, firstSplit);
line.erase(0, firstSplit+gSpy.CmdSplit.length());
// 处理指令
processCmd(sock, cmd, line);
}
}
std::map<std::string, std::string> FileSpy::parseArgs(std::string &data)
{
// 字符串分割成列表
std::vector<std::string> v;
std::string::size_type pos1, pos2;
pos2 = data.find(gSpy.CmdSplit);
pos1 = 0;
while(std::string::npos != pos2) {
v.push_back(data.substr(pos1, pos2-pos1));
pos1 = pos2 + gSpy.CmdSplit.size();
pos2 = data.find(gSpy.CmdSplit, pos1);
}
if(pos1 != data.length()) v.push_back(data.substr(pos1));
// 解析参数
std::map<std::string, std::string> args;
for (int i=0; i<(int)v.size()-1; i+=2) {
args[v.at(i)] = v.at(i+1);
}
return args;
}
void FileSpy::processCmd(TcpSocket *sock, std::string &cmd, std::string &data)
{
// 解析参数
std::map<std::string, std::string> args = parseArgs(data);
// 获取文件
if (cmd == gSpy.CmdGetDirFiles) {
doGetDirFiles(sock, args);
return;
}
// 下载文件
if (cmd == gSpy.CmdDownloadFile) {
doDownloadFile(sock, args);
return;
}
// 上传文件
if (cmd == gSpy.CmdUploadFile) {
doUploadFile(sock, args);
return;
}
// 删除文件
if (cmd == gSpy.CmdDeleteFile) {
doDeleteFile(sock ,args);
return;
}
}
void FileSpy::doGetDirFiles(TcpSocket *sock, std::map<std::string, std::string> &args)
{
std::string dir = args["DIR"];
std::string data;
// 如果为空就代表获取盘符
if (dir.size() == 0) {
std::vector<std::string> drives;
drives = getDrives();
// 把盘符打包成数据
data.append(gSpy.CmdSendDrives+gSpy.CmdSplit);
data.append("DRIVES"+gSpy.CmdSplit);
int max = drives.size();
for (int i=0; i<max; ++i) {
data.append(drives[i]+gSpy.CmdFileSplit);
}
if (drives.size() > 0) {
data.erase(data.size()-1);
}
data.append(gSpy.CmdEnd);
// 发送
sock->sendData(data.data(), data.size());
} else {
std::vector<std::string> files;
std::vector<std::string> dirs;
dirs = getDirs(dir);
files = getFiles(dir);
// 把目录打包成数据
data.append(gSpy.CmdSendDirs+gSpy.CmdSplit);
data.append("DIR"+gSpy.CmdSplit+ dir +gSpy.CmdSplit);
data.append("DIRS"+gSpy.CmdSplit);
int max = dirs.size();
for (int i=0; i<max; ++i) {
data.append(dirs[i]+gSpy.CmdFileSplit);
}
if (dirs.size() > 0) {
data.erase(data.size()-1);
}
data.append(gSpy.CmdEnd);
// 把文件名打包成数据
data.append(gSpy.CmdSendFiles+gSpy.CmdSplit);
data.append("DIR"+gSpy.CmdSplit+ dir +gSpy.CmdSplit);
data.append("FILES"+gSpy.CmdSplit);
max = files.size();
for (int i=0; i<max; ++i) {
data.append(files[i]+gSpy.CmdFileSplit);
}
if (files.size()) {
data.erase(data.size()-1);
}
data.append(gSpy.CmdEnd);
// 发送
sock->sendData(data.data(), data.size());
}
}
void FileSpy::doDownloadFile(TcpSocket *sock, std::map<std::string, std::string> &args)
{
// 发送文件到服务端
std::string filePath = args["FILE_PATH"];
int port = atoi(args["PORT"].data());
// 开启一个新的线程发送文件
startSendFileByNewThread(filePath, sock->mIp, port);
}
void FileSpy::doUploadFile(TcpSocket *sock, std::map<std::string, std::string> &args)
{
// 从服务端接收文件
std::string filePath = args["FILE_PATH"];
int port = atoi(args["PORT"].data());
// 开启一个线程接收文件
startRecvFileByNewThread(filePath, sock->mIp, port);
}
void FileSpy::doDeleteFile(TcpSocket *sock, std::map<std::string, std::string> &args)
{
// 删除文件
bool ret = DeleteFileA(args["FILE_PATH"].data());
std::string data;
if (ret) {
data.append(gSpy.CmdDeleteFileSuccess);
data.append(gSpy.CmdEnd);
sock->sendData(data.data(), data.size());
} else {
data.append(gSpy.CmdDeleteFileFailed);
data.append(gSpy.CmdEnd);
sock->sendData(data.data(), data.size());
}
}
std::vector<std::string> FileSpy::getDrives()
{
std::vector<std::string> drives;
// 遍历a-z盘符
for (int i='b'; i<='z'; i++) {
char d[MAX_PATH];
sprintf(d, "%c:\\*", i);
WIN32_FIND_DATAA findData;
HANDLE h = FindFirstFileA(d, &findData);
if (h != INVALID_HANDLE_VALUE) {
d[strlen(d)-1] = '\0';
drives.push_back(d);
// 释放句柄
CloseHandle(h);
}
}
return drives;
}
std::vector<std::string> FileSpy::getDirs(std::string dir)
{
WIN32_FIND_DATAA findData;
HANDLE hFind = FindFirstFileA(dir.append("\\*").data(), &findData);
std::vector<std::string> files;
if (hFind == INVALID_HANDLE_VALUE) {
return files;
}
// 遍历目录来获取路径
while (FindNextFileA(hFind, &findData)) {
// 不需要后退和当前目录
if(!strcmp(findData.cFileName,"..") || !strcmp(findData.cFileName,".")) {
continue;
}
// 判断路径
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
files.push_back(findData.cFileName);
}
}
// 释放句柄
CloseHandle(hFind);
return files;
}
std::vector<std::string> FileSpy::getFiles(std::string dir)
{
WIN32_FIND_DATAA findData;
HANDLE hFind = FindFirstFileA(dir.append("\\*").data(), &findData);
std::vector<std::string> files;
if (hFind == INVALID_HANDLE_VALUE) {
return files;
}
// 遍历目录来获取文件
while (FindNextFileA(hFind, &findData)) {
// 不需要后退和当前目录
if(!strcmp(findData.cFileName,"..") || !strcmp(findData.cFileName,".")) {
continue;
}
// 判断不是路径
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
files.push_back(findData.cFileName);
}
}
// 释放句柄
CloseHandle(hFind);
return files;
}
void FileSpy::startSendFileByNewThread(std::string filePath, std::string domain, int port)
{
// 将文件路径,域名和端口数据转换成一个字符指针类型
char *args = new char[MAX_PATH+MAX_PATH+sizeof(int)];
filePath.reserve(MAX_PATH);
memcpy(args, filePath.data(), MAX_PATH);
domain.reserve(MAX_PATH);
memcpy(args+MAX_PATH,domain.data(), MAX_PATH);
memcpy(args+MAX_PATH+MAX_PATH,(char*)&port, sizeof(int));
// 创建新线程
HANDLE h = CreateThread(NULL,0, FileSpy::sendFileThreadProc,(LPVOID)args,0,NULL);
if (!h) {
std::cout << "Failed to create new thread" << std::endl;
std::fflush(stdout);
}
}
DWORD FileSpy::sendFileThreadProc(LPVOID args)
{
// 将文件路径,域名和端口数据从指针转换过来
char filePath[MAX_PATH], domain[MAX_PATH];
memcpy(filePath, args, MAX_PATH);
memcpy(domain, args+MAX_PATH, MAX_PATH);
int port = *((int*)((char*)args+MAX_PATH+MAX_PATH));
// 开始发送文件
startSendFile(filePath, domain, port);
// 释放参数
delete (char *)args;
return true;
}
void FileSpy::startSendFile(std::string filePath, std::string domain, int port)
{
// 连接到服务端发送文件
TcpSocket sock;
if (!sock.connectTo(domain, port)) {
std::cout << "Failed to connect server for send file" << std::endl;
std::fflush(stdout);
return;
}
// 打开文件
FILE *fp = fopen(filePath.data(), "rb");
if (!fp) {
// 断开
sock.dissconnect();
std::cout << "Failed to open file for send file" << std::endl;
std::fflush(stdout);
return;
}
// 获取文件大小
fseek(fp, 0, SEEK_END);
unsigned int len = ftell(fp);
rewind(fp);
// 获取文件名字
char name[_MAX_FNAME], ext[_MAX_EXT];
_splitpath(filePath.data(), NULL, NULL, name, ext);
// 发送文件头
FileHeader header;
sprintf(header.fileName, "%s%s", name,ext);
header.len = len;
sock.sendData((char *)&header, sizeof(header));
// 发送文件数据
// 发送jpg数据包,包大小每次最好少于1000,我这里定义800
const unsigned int paketLen = 800;
char data[800];
unsigned int pos = 0;
while (pos < len) {
int sendSize = (pos+paketLen) > len ? len-pos : paketLen;
// 读取文件
fread(data, 1, sendSize, fp);
if (!sock.sendData(data, sendSize)) {
return;
}
pos += sendSize;
}
// 关闭已经打开的文件
fclose(fp);
}
void FileSpy::startRecvFileByNewThread(std::string filePath, std::string domain, int port)
{
// 将文件路径,域名和端口数据转换成一个字符指针类型
char *args = new char[MAX_PATH+MAX_PATH+sizeof(int)];
filePath.reserve(MAX_PATH);
memcpy(args, filePath.data(), MAX_PATH);
domain.reserve(MAX_PATH);
memcpy(args+MAX_PATH,domain.data(), MAX_PATH);
memcpy(args+MAX_PATH+MAX_PATH,(char*)&port, sizeof(int));
// 创建新线程
HANDLE h = CreateThread(NULL,0, FileSpy::recvFileThreadProc,(LPVOID)args,0,NULL);
if (!h) {
std::cout << "Failed to create new thread" << std::endl;
std::fflush(stdout);
}
}
DWORD FileSpy::recvFileThreadProc(LPVOID args)
{
// 将文件路径,域名和端口数据从指针转换过来
char filePath[MAX_PATH], domain[MAX_PATH];
memcpy(filePath, args, MAX_PATH);
memcpy(domain, args+MAX_PATH, MAX_PATH);
int port = *((int*)((char*)args+MAX_PATH+MAX_PATH));
// 开始接收
startRecvFile(filePath, domain, port);
// 释放参数
delete (char *)args;
return true;
}
void FileSpy::startRecvFile(std::string filePath, std::string domain, int port)
{ // 连接到服务端发送文件
TcpSocket sock;
if (!sock.connectTo(domain, port)) {
std::cout << "Failed to connect server for send file" << std::endl;
std::fflush(stdout);
return;
}
// 创建一个新的文件
FILE *fp = fopen(filePath.data(), "wb");
if (!fp) {
// 断开
sock.dissconnect();
std::cout << "Failed to open file for send file" << std::endl;
std::fflush(stdout);
return;
}
// 开始接收数据
const int packetLen = 800;
char data[packetLen];
while(1) {
int ret = sock.recvData(data, packetLen);
if (ret == SOCKET_ERROR || ret == 0) {
break;
}
// 写入数据
fwrite(data, 1, ret, fp);
}
// 关闭文件
if (fp) {
fclose(fp);
}
}
这一节的完整代码:
下载