12.4 组播鼠标批量执行

组播模式相比单播模式可以提高网络的效率和带宽利用率,因为组播数据包只需要发送一次,就可以被多个接收者接收,而不需要每个接收者都单独发送一份数据包。这在需要同时向多个接收者发送相同数据的场景下特别有用,如视频会议、在线教育、流媒体等。组播模式可以减少网络拥塞,降低网络延迟,并且可以减少网络中的冗余数据。

通过构建组播服务器端与客户端,并配合键盘鼠标控制接口,当服务器端执行一个操作时客户端同步执行,通过此方法读者可轻易的实现一个简单的镜像服务器,当服务器规模庞大而主机系统版本相同时,该功能可实现服务器端执行一次客户端即可实现批量部署的效果。

先来看服务端是如何实现的功能,首先服务端定义umsg结构体,该结构用于存储鼠标坐标值以及鼠标按键状态,当服务器运行后开启组播模式等待客户端上线,当客户端上线则我们通过动态获取本机鼠标位置并封装成结构体传输给上线的客户端,以此来实现镜像功能。

#include <winsock.h>
#include <iostream>#pragma comment(lib, "WSOCK32.lib")using namespace std;// 鼠标状态结构体
typedef struct umsg
{int cursor_pos_x;           // 鼠标X坐标int cursor_pos_y;           // 鼠标Y坐标int cursor_key_state;       // 鼠标按键状态umsg() :cursor_pos_x(), cursor_pos_y(), cursor_key_state(){cursor_pos_x = 0;cursor_pos_y = 0;cursor_key_state = 0;}
}umsg;// 获取鼠标按键
int GetKeyState()
{if (GetAsyncKeyState(VK_LBUTTON) & 0x8000){Sleep(15);return 1;}if (GetAsyncKeyState(VK_RBUTTON) & 0x8000){Sleep(15);return 2;}return 0;
}int main(int argc, char *argv[])
{WSADATA wsaData;struct sockaddr_in addr;int fd;struct ip_mreq mreq;// 初始化套接字if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){std::cout << "初始化失败" << std::endl;return 0;}// 创建套接字 SOCK_DGRAM 采用UDPif ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){std::cout << "套接字创建失败" << std::endl;return 0;}// 设置套接字为组播模式u_int yes = 1;if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0){std::cout << "设置组播模式失败" << std::endl;return 0;}// 0-同一台主机,1-跨主机UCHAR uLoop = 1;setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&uLoop, sizeof(uLoop));memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_addr.s_addr = htonl(INADDR_ANY);addr.sin_port = htons(9999);// 绑定套接字if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0){std::cout << "绑定失败" << std::endl;return 0;}// 设置组播模式中的组信息mreq.imr_multiaddr.s_addr = inet_addr("228.2.3.1");mreq.imr_interface.s_addr = htonl(INADDR_ANY);if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0){int err = GetLastError();std::cout << "设置组失败: " << err << std::endl;return 0;}// 循环while (1){char recv_buffer[4096] = { 0 };char send_buffer[4096] = { 0 };int addrlen = sizeof(addr);int nbytes;// 接收组播数据if ((nbytes = recvfrom(fd, recv_buffer, 4096, 0, (struct sockaddr *) &addr, (int *)&addrlen)) < 0){std::cout << "接收数据包失败" << std::endl;return 0;}recv_buffer[nbytes] = '\0';std::cout << "接收组播数据包: " << recv_buffer << std::endl;umsg msg;// 获取鼠标状态POINT pt;BOOL ref = GetCursorPos(&pt);// 设置鼠标坐标msg.cursor_pos_x = pt.x;msg.cursor_pos_y = pt.y;// 获取鼠标状态值int key_flag = GetKeyState();if (key_flag == 0){msg.cursor_key_state = 0;}else if (key_flag == 1){msg.cursor_key_state = 1;}else if (key_flag == 2){msg.cursor_key_state = 2;}std::cout << "鼠标X = " << msg.cursor_pos_x << " 鼠标Y = " << msg.cursor_pos_y << std::endl;std::cout << "鼠标键位 = " << msg.cursor_key_state << std::endl;// 发送组播数据包sendto(fd, (char *)&msg, 4096, 0, (struct sockaddr *) &addr, sizeof(addr));}return 0;
}

与服务端功能类似,对于客户端来说,收到数据包以后,将其转换为umsg格式结构体,读取其中坐标信息,并执行指定函数对鼠标的状态进行设置,实现鼠标的同步执行。

#include <winsock.h>
#include <iostream>#pragma comment(lib, "WSOCK32.lib")using namespace std;// 鼠标状态结构体
typedef struct umsg
{int cursor_pos_x;           // 鼠标X坐标int cursor_pos_y;           // 鼠标Y坐标int cursor_key_state;       // 鼠标按键状态umsg() :cursor_pos_x(), cursor_pos_y(), cursor_key_state(){cursor_pos_x = 0;cursor_pos_y = 0;cursor_key_state = 0;}
}umsg;int main(int argc, char *argv[])
{WSADATA wsaData;struct sockaddr_in addr;int fd;// 初始化套接字if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){std::cout << "初始化失败" << std::endl;return 0;}// 创建套接字 SOCK_DGRAM 采用UDPif ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){std::cout << "套接字创建失败" << std::endl;return 0;}UCHAR uLoop = 1; // 0-同一台主机,1-跨主机setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&uLoop, sizeof(uLoop));// 设置组播模式组信息memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr("228.2.3.1");addr.sin_port = htons(9999);// 循环while (1){// 发送组播数据包char send_buffer[4096] = "Hello, World!";if (sendto(fd, send_buffer, strlen(send_buffer), 0, (struct sockaddr *) &addr, sizeof(addr)) < 0){std::cout << "发送失败" << std::endl;return 0;}// 接收组播数据int addrlen = sizeof(addr);char recv_buffer[4096] = { 0 };recvfrom(fd, recv_buffer, 4096, 0, (struct sockaddr *) &addr, (int *)&addrlen);std::cout << "接收组播数据包: " << recv_buffer << std::endl;// 格式化数据包为umsg格式umsg* recv_message = (umsg*)recv_buffer;int pos_x = recv_message->cursor_pos_x;int pos_y = recv_message->cursor_pos_y;int key_stat = recv_message->cursor_key_state;// 判断键位并设置if (key_stat == 0){std::cout << "鼠标X: " << pos_x << " 鼠标Y: " << pos_y << endl;SetCursorPos(pos_x, pos_y);}else if (key_stat == 1){std::cout << "左键按下" << std::endl;mouse_event(MOUSEEVENTF_LEFTUP | MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);key_stat = 0;}else if (key_stat == 2){std::cout << "右键按下" << std::endl;mouse_event(MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);key_stat = 0;}}return 0;
}

读者可以编译上方两段代码,并首先在物理机内启动服务端,在虚拟机内启动客户端,此时当服务端鼠标发生移动时客户端也会跟随移动,服务端执行的操作客户端也会被执行,如下图所示;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/ae8bf78c.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/117352.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

矢量图形编辑软件 illustrator 2023 mac 中文软件特点

illustrator 2023 mac是一款矢量图形编辑软件&#xff0c;用于创建和编辑排版、图标、标志、插图和其他类型的矢量图形。 illustrator 2023 mac软件特点 矢量图形&#xff1a;illustrator创建的图形是矢量图形&#xff0c;可以无限放大而不失真&#xff0c;这与像素图形编辑软…

Ubuntu - sudo apt update 报错源问题解决方案

sudo apt update 报错…lease’ does not have a Release file. 反正就是觉得是网络的问题 尝试添加国内清华源、阿里源 不行 尝试DNS 为8.8.8.8&#xff0c;114.114.114.114 还是不行 解决方案&#xff1a;设置里面让 Ubuntu 找到适合自己的源 1、Settings -> About…

分布式限流:Redis

目录 1:如何实现分布式限流 2:限流的几种类别 2.1:固定窗口限流 2.2:滑动窗口限流 2.3:漏桶限流 2.4:令牌桶限流 3:实现分布式限流:Redis 3.1:引入Redisson的依赖包 3.2:初始化Redisson 3.3:创建Redisson的限流类 1:如何实现分布式限流 1:把统计用户的使用频率等这些…

Spark简单回顾

星光下的赶路人star的个人主页 大鹏一日同风起&#xff0c;扶摇直上九万里 文章目录 1、Spark1.1 Spark入门1.1.1 Spark部署模式1.1.2 常用端口 1.2 SparkCore1.2.1 RDD不可变和五大属性1.2.2 RDD的弹性1.2.3 cache和Checkpoint的区别1.2.4 算子 1.3 SparkSQL1.4 内核1.4.1提交…

lv8 嵌入式开发-网络编程开发 20 域名解析与http服务实现原理

目录 1 域名解析 2 如何实现万维网服务器&#xff1f; 2.1 HTTP 的操作过程 2.2 万维网服务器实现 1 域名解析 域名解析gethostbyname函数 主机结构在 <netdb.h> 中定义如下&#xff1a; struct hostent {char *h_name; /* 官方域名 */char **h_alias…

hadoop伪分布式安装部署

首先jdk安装完毕 jdk安装文档参考&#xff1a; Linux 环境下安装JDK1.8并配置环境变量_linux安装jdk1.8并配置环境变量_Xi-Yuan的博客-CSDN博客 准备好hadoop的安装包 我的下载地址如下&#xff1a; We Transfer Gratuit. Envoi scuris de gros fichiers. 将hadoop包上传到随…

Redis数据类型——hash类型的概念及操作

1.hash类型介绍 可以理解为redis中的一个小型redis 2.v 3.hash数据类型的扩展操作 4.hash类型数据操作的注意事项

WPF中的绑定知识详解(含案例源码分享)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

C/C++新冠疫情死亡率 2020年9月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C新冠疫情死亡率 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C新冠疫情死亡率 2020年9月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 2020年全世界爆发了新冠疫情&#xff0c;请…

基于定容积法标准容器容积标定中的电动针阀自动化解决方案

摘要&#xff1a;在目前的六氟化硫气体精密计量中普遍采用重量法和定容法两种技术&#xff0c;本文分析了重量法中存在的问题以及定容法的优势&#xff0c;同时也指出定容法在实际应用中还存在自动化水平较低的问题。为了提高定容法精密计量过程中的自动化水平&#xff0c;本文…

睿趣科技:抖音小店申请流程

随着移动互联网的发展&#xff0c;越来越多的人开始尝试通过开设网店来创业。抖音作为国内最受欢迎的短视频平台之一&#xff0c;也推出了自己的电商功能——抖音小店。那么&#xff0c;如何申请抖音小店呢?下面就为大家详细介绍一下抖音小店的申请流程。 首先&#xff0c;打开…

docker环境,ubuntu18.04安装VTK8.2和PCL1.9.1

下载源码和依赖库 首先下载源码VTK8.2: Download | VTK 下载PCL1.9.1链接&#xff1a;Releases PointCloudLibrary/pcl GitHub 下载好了以后&#xff0c;先安装PCL依赖 sudo apt-get update sudo apt-get install git build-essential linux-libc-dev sudo apt-get instal…

算法通关村第十一关白银挑战——位运算符的高频算法题

大家好&#xff0c;我是怒码少年小码。 今天讲讲几个位运算的经典算法。 位移的妙用 1. 位1的个数 LeetCode 191&#xff1a;编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中数字位数为 ‘1’ 的个…

Spring Boot集成RESTful API

在Spring Boot中集成一个RESTful API是我们在实际开发中较为常见的一种开发任务&#xff0c;以下通过一个小的案例来展示在Spring Boot中创建RESTful API来编写一个单元测试。 本节使用到的注解&#xff1a; Controller&#xff1a;修饰class&#xff0c;用来创建处理http请求的…

互联网Java工程师面试题·Spring篇·第四弹

目录 6、AOP 6.1、什么是 AOP&#xff1f; 6.2、什么是 Aspect&#xff1f; 6.3、什么是切点&#xff08;JoinPoint&#xff09; 6.4、什么是通知&#xff08;Advice&#xff09;&#xff1f; 6.5、有哪些类型的通知&#xff08;Advice&#xff09;&#xff1f; 6.6、指出…

Fedora系统的部署与MobaXterm的使用

Fedora Fedora简介 Fedora&#xff0c;Fedora Linux&#xff08;第七版以前为Fedora Core&#xff09;是由Fedora项目社区开发、红帽公司赞助&#xff0c;目标是创建一套新颖、多功能并且自由&#xff08;开放源代码&#xff09;的操作系统。Fedora是商业化的Red Hat Enterpr…

正点原子嵌入式linux驱动开发——Linux INPUT子系统

按键、鼠标、键盘、触摸屏等都属于输入(input)设备&#xff0c;Linux内核为此专门做了一个叫做input子系统的框架来处理输入事件。输入设备本质上还是字符设备&#xff0c;只是在此基础上套上了input框架&#xff0c;用户只需要负责上报输入事件&#xff0c;比如按键值、坐标等…

如何在Android Termux上安装MySQL并实现公网远程访问?

文章目录 前言1.安装MariaDB2.安装cpolar内网穿透工具3. 创建安全隧道映射mysql4. 公网远程连接5. 固定远程连接地址 前言 Android作为移动设备&#xff0c;尽管最初并非设计为服务器&#xff0c;但是随着技术的进步我们可以将Android配置为生产力工具&#xff0c;变成一个随身…

使用Vscode创建一个C_Hello程序

Vscode用来学习C语言语法确实很方便。问题是安装好了&#xff0c;不会用&#xff0c;或编译失败&#xff0c;也是常有的事情&#xff0c;其中一个原因就是不会创建工作区。下面介绍使用Vscode创建一个C语言工作区。有时候看着很简单&#xff0c;时间久了&#xff0c;我竟然忘记…

Centos8: 安装python2, 并设置默认版本

文章目录 原本centos上已经有python3.6了&#xff0c;因为要运行旧代码&#xff0c;需要安装python2版本。 #在CentOS 8上安装Python 2 sudo dnf install python2#设置默认Python版本 python2 sudo alternatives --set python /usr/bin/python2#设置默认Python版本 python3 sud…