C++socket套接字编程以及模拟键鼠操作的总结
2016-12-05 15:32
369 查看
前段时间在接了一个小任务,要求是监听一个文件夹,如果文件夹中的文件发生变化,就读取其中的txt文件,并且通过自己设计的发送端将需要的数据发送到公网中指定的另一个计算机,而那台计算机的接收端接收到数据之后就模拟键盘鼠标事件,向一个客户端中输入传递过来的数据,全程不需要人的操作,我之前在学校的时候学习过socket套接字编程,但只是最简单的在自己电脑上试验,以为会很简单,但是在项目做起来的时候发现了超级多的问题,我写这个第一个是为了总结下自己这段时间的工作,第二个是希望有类似问题的人看见后会有些帮助
1.监听文件夹。
这里是比较简单的。首先将需要监听的文件夹绑定句柄。具体代码如下:
这里需要注意的就是ReadDirectoryChangesW()这个函数一般使用情况是阻塞的,如果想要异步监听文件变化的话,打开方式设置参数为FILE_FLAG_OVERLAPPED ,并且需要制定参数 OVERLAPPED ,通过 OVERLAPPED 参数来判断是否文件夹发生了变化。将OVERLAPPED替换倒数第二个参数null。并且通过GetOverlappedResult()函数来得到结果。具体使用情况
而如果文件夹中有多个文件的时候,要依次读取文件中的数据,这时候就使用如下的函数,需要注意的就是他第一读取的不是文件夹里的第一个文件名,所以需要自己另写函数进行筛选。
http://blog.csdn.net/wzsy/article/details/6697613
这里面解释的比较详细。
监听文件夹之后如果文件夹中出现了txt文件就读取其中的数据,读取数据这块我就不再多说了。
下面就是使用socket套接字传递数据
2.socket套接字
socket套接字在网络上的教程和代码已经很多很详细了,我就不再说具体的流程和过程了,而这里我想说的就是我因为是第一次使用外网进行socket之间的通信,所以这里我思考了很久如何在外网中通讯,因为现在都是动态IP,不太可能每次都询问对方的IP,所以这里的解决办法就是绑定域名,而我使用的是花生壳,将IP地址和端口号都设置成花生壳提供的就可以在外网中进行访问和数据的发送了
3.在接收端接收到数据之后,就要将接收的数据进行键盘鼠标事件模拟,电脑自动将数据输入到指定的文件或者应用程序中
使用mouse_event()模拟鼠标事件,使用keybd_event()模拟键盘触发事件,这里要注意的就是每次模拟时按下和放开是两个分别独立的,也就是在模拟按下操作之后也需要模拟松开操作
具体参数是什么到网上寻找很全。只需要进行相应的替换即可。
但是我这里要说的就是,我这里要模拟的是很长的一段数字或者英文的输入,这就会存在一个问题,就是在每次模拟键盘输入和下一次键盘输入之间要设置好时间间隔,也就是需要sleep()一段时间,我这里sleep的时间是0.1秒也就是sleep(100),要不然就会出现上一次输入被下一次输入替代掉,这样就是使原本需要模拟的键盘输入的字符串发生混乱,如需要模拟键盘输入1234567890,但是如果每个输入之间不设置间隔的话,很可能就是135790,或者干脆就是10,具体就要看电脑的处理能力了,所以设置按键之间的暂停时间是有必要的。
键盘鼠标事件相关参数说明推荐:
http://www.cnblogs.com/Vicky-Lee/archive/2011/09/15/2177761.html
1.监听文件夹。
这里是比较简单的。首先将需要监听的文件夹绑定句柄。具体代码如下:
DWORD cbBytes; char file_name[MAX_PATH]; //设置文件名; char file_rename[MAX_PATH]; //设置文件重命名后的名字; char notify[1024]; int count = 0; //文件数量。可能同时拷贝、删除多个文件,可以进行更友好的提示; TCHAR *dir = _T("F:\\test"); HANDLE dirHandle = CreateFile(dir,GENERIC_READ | GENERIC_WRITE | FILE_LIST_DIRECTORY,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL); if (dirHandle == INVALID_HANDLE_VALUE) //若网络重定向或目标文件系统不支持该操作,函数失败,同时调用GetLastError()返回ERROR_INVALID_FUNCTION { cout << "文件路径不存在" + GetLastError() << endl; } memset(notify, 0, strlen(notify)); FILE_NOTIFY_INFORMATION *pnotify = (FILE_NOTIFY_INFORMATION*)notify; listen(servSock, 20); if (ReadDirectoryChangesW(dirHandle, ¬ify, 1024, true, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE, &cbBytes, NULL, NULL)) { cout << "文件发生改变" << endl; //转换文件名为多字节字符串; if (pnotify->FileName) { memset(file_name, 0, strlen(file_name)); WideCharToMultiByte(CP_ACP, 0, pnotify->FileName, pnotify->FileNameLength / 2, file_name, 99, NULL, NULL); memset(file_name, 0, strlen(file_name)); WideCharToMultiByte(CP_ACP, 0, pnotify->FileName, pnotify->FileNameLength / 2, file_name, 99, NULL, NULL); } //获取重命名的文件名; if (pnotify->NextEntryOffset != 0 && (pnotify->FileNameLength > 0 && pnotify->FileNameLength < MAX_PATH)) { PFILE_NOTIFY_INFORMATION p = (PFILE_NOTIFY_INFORMATION)((char*)pnotify + pnotify->NextEntryOffset); memset(file_rename, 0, sizeof(file_rename)); WideCharToMultiByte(CP_ACP, 0, p->FileName, p->FileNameLength / 2, file_rename, 99, NULL, NULL); } string filepath; char file_path[50]; //设置类型过滤器,监听文件创建、更改、删除、重命名等; switch (pnotify->Action) { case FILE_ACTION_ADDED: count++; cout << setw(5) << "添加文件:" << setw(5) << file_name << endl; filepath= "F:\\test\\" + (string)file_name; strcpy(file_path, filepath.c_str()); cout <<"文件路径:" <<file_path; break; case FILE_ACTION_MODIFIED: cout << "file modified:" << setw(5) << file_name << endl; break; case FILE_ACTION_REMOVED: count++; cout << count << setw(5) << "删除文件:" << setw(5) << file_name << endl; break; case FILE_ACTION_RENAMED_OLD_NAME: cout << "文件重命名为:" << setw(5) << file_name << "->" << file_rename << endl; break; default: cout << "未知命令!" << endl; } }
这里需要注意的就是ReadDirectoryChangesW()这个函数一般使用情况是阻塞的,如果想要异步监听文件变化的话,打开方式设置参数为FILE_FLAG_OVERLAPPED ,并且需要制定参数 OVERLAPPED ,通过 OVERLAPPED 参数来判断是否文件夹发生了变化。将OVERLAPPED替换倒数第二个参数null。并且通过GetOverlappedResult()函数来得到结果。具体使用情况
而如果文件夹中有多个文件的时候,要依次读取文件中的数据,这时候就使用如下的函数,需要注意的就是他第一读取的不是文件夹里的第一个文件名,所以需要自己另写函数进行筛选。
WIN32_FIND_DATA wfd; HANDLE 4000 hFind; char filepath[50]//文件夹路径 hFind = FindFirstFile(filepath, &wfd); cout << "文件名" << wfd.cFileName << endl; do { //需要执行的内容 } } while (FindNextFile(hFind, &wfd)); FindClose(hFind);
http://blog.csdn.net/wzsy/article/details/6697613
这里面解释的比较详细。
监听文件夹之后如果文件夹中出现了txt文件就读取其中的数据,读取数据这块我就不再多说了。
下面就是使用socket套接字传递数据
2.socket套接字
socket套接字在网络上的教程和代码已经很多很详细了,我就不再说具体的流程和过程了,而这里我想说的就是我因为是第一次使用外网进行socket之间的通信,所以这里我思考了很久如何在外网中通讯,因为现在都是动态IP,不太可能每次都询问对方的IP,所以这里的解决办法就是绑定域名,而我使用的是花生壳,将IP地址和端口号都设置成花生壳提供的就可以在外网中进行访问和数据的发送了
3.在接收端接收到数据之后,就要将接收的数据进行键盘鼠标事件模拟,电脑自动将数据输入到指定的文件或者应用程序中
使用mouse_event()模拟鼠标事件,使用keybd_event()模拟键盘触发事件,这里要注意的就是每次模拟时按下和放开是两个分别独立的,也就是在模拟按下操作之后也需要模拟松开操作
keybd_event(VK_RETURN, 0, 0, 0); keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);//模拟回车,其他案件也是同样的道理,每一个案件都对应着不同的参数 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);//模拟鼠标操作事件,原理同上
具体参数是什么到网上寻找很全。只需要进行相应的替换即可。
但是我这里要说的就是,我这里要模拟的是很长的一段数字或者英文的输入,这就会存在一个问题,就是在每次模拟键盘输入和下一次键盘输入之间要设置好时间间隔,也就是需要sleep()一段时间,我这里sleep的时间是0.1秒也就是sleep(100),要不然就会出现上一次输入被下一次输入替代掉,这样就是使原本需要模拟的键盘输入的字符串发生混乱,如需要模拟键盘输入1234567890,但是如果每个输入之间不设置间隔的话,很可能就是135790,或者干脆就是10,具体就要看电脑的处理能力了,所以设置按键之间的暂停时间是有必要的。
键盘鼠标事件相关参数说明推荐:
http://www.cnblogs.com/Vicky-Lee/archive/2011/09/15/2177761.html
相关文章推荐
- Symbian编程总结-网络与通信-套接字(1)-套接字体系结构与相关API
- Symbian编程总结-网络与通信-套接字(1)-套接字体系结构与相关API
- objective-c 编程总结(第七篇)运行时操作 - 动态属性
- VC操作Excel文件编程相关内容总结
- 关于myeclipse操作中出现的自动提示,以及误报错误问题总结
- 编程swing技巧总结:当在frame中弹出对话框dialog,先完成dialog的操作,才继续往下进行。
- UNP总结 Chapter 4 基本TCP套接字编程
- objective-c 编程总结(第五篇)集合类型操作
- objective-c 编程总结(第四篇)日期型类型操作
- C++socket编程基础总结
- Symbian编程总结-网络与通信-套接字(1)-套接字体系结构与相关API
- Linux 套接字编程-基础总结
- VC操作Excel文件编程相关内容总结
- objective-c 编程总结(第六篇)运行时操作 - 方法交换
- oracle编程、操作不良习惯总结
- 关于Hibernate操作数据库为空(数值类型)以及引起的问题的一点点总结
- Ajax程序模拟SOCKET套接字编程
- [CF Skills]如何编程模拟用户的触屏操作
- objective-c 编程总结(第九篇)运行时操作 - 序列化
- 多线程操作--模拟二维码的扫描以及定期存储