首页 > 其他分享 >12.4 组播鼠标批量执行

12.4 组播鼠标批量执行

时间:2023-10-24 09:02:21浏览次数:35  
标签:组播 鼠标 int pos cursor key 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 采用UDP
  if ((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 采用UDP
  if ((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 许可协议。转载请注明出处!

标签:组播,鼠标,int,pos,cursor,key,12.4,客户端
From: https://www.cnblogs.com/LyShark/p/17783929.html

相关文章

  • 《最新出炉》系列初窥篇-Python+Playwright自动化测试-21-处理鼠标拖拽-番外篇
    1.简介前边宏哥拖拽有提到那个反爬虫机制,加了各种参数,以及加载js脚本文件还是有问题,偶尔宏哥好像发现了解决问题的办法,看到了黎明的曙光,宏哥就说试一下看看行不行,万一实现了。结果宏哥试了结果真的OK啊,但是宏哥第一次运行可以,后边就不行了,然后将编辑器关闭重启,再次运行又可以,宏哥......
  • OSPF组播地址理解
    OSPF(OpenShortestPathFirst)使用组播地址来进行邻居发现和LSA(LinkStateAdvertisement)更新的通信。OSPF的组播地址是224.0.0.5。以下是对OSPF组播地址的详细说明及其工作过程:组播地址:IPv4组播地址用于将数据报发送到一个组中的所有成员。OSPF使用组播地址224.0.0.5作为邻居发现......
  • C#实现鼠标进入按键范围后按键自动窗体内位置移动
    新建winform窗体程序添加button控件 在事件中选择MouseEnter 代码如下privatevoidbutton_MouseEnter(objectsender,EventArgse){//给按钮一个新的坐标//这个按钮活动的最大宽度就是窗体的宽度减去按钮的宽度intx=this.ClientSize.Width-button.Widt......
  • CSS 实现鼠标悬浮边框线动画效果
    一、transitionCSStransition(过渡效果)详解CSS中提供了5个有关过渡的属性,如下所示:transition-property:设置元素中参与过渡的属性;transition-duration:设置元素过渡的持续时间;transition-timing-function:设置元素过渡的动画类型;transition-delay:设置过渡效果延迟的时间,默......
  • 记录--怎么写一个可以鼠标控制旋转的div?
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助说在前面鼠标控制元素旋转在现在也是一个很常见的功能,让我们从实现div元素的旋转控制开始来了解元素旋转的具体原理和实现方法吧。效果展示体验地址code.juejin.cn/pen/7290719…实现步骤画一个div首先我......
  • 视频监控管理平台EasyCVR二级菜单隐藏后,鼠标悬浮时菜单名称不显示该如何解决?
    安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台可拓展性强、视频能力灵活,能对外分发RTMP、RTSP、HTTP-......
  • 计算机出现鼠标出现乱跳问题(USB485模块识别为鼠标设备)
    原因:计算机把USB485模块识别成“串口鼠标设备”,先给485上电。由于串口上一直有485数据,系统启动时候,误认为串口发送的数据是鼠标数据,从而把串口设备识别成了鼠标设备。解决方法:禁用注册表中sermouse的启动项。具体步骤:1、键盘(win+R),出现运行窗口,输入regedit,回车进入注册表编辑器......
  • selenium之鼠标操作详解
    前言人类频繁的用手操作鼠标和键盘,为了解决这个问题,selenium工具为我们提供了一个类来处理这些事件—Actionchains,该类可以完成鼠标移动,鼠标点击事件、键盘输入、内容菜单交互等交互行为。1、常见的鼠标操作有:单击、右键点击、双击、移动鼠标、拖拽鼠标。(Actionchains代替人......
  • vue移动鼠标画矩形(抄别人的,下附原文地址)
    1、draw.js/***画布中绘制矩形*参数:cav-画布对象list-矩形数组i-选中矩形下标**//*操作执行方法分发*/exportfunctiondraw(cav,list,i){//画布初始化letctx=cav.getContext('2d');ctx.strokeStyle='blue';ctx.lineWidth=2;......
  • (CH592-CH305)2K鼠标上报率
    前言:使用CH592与CH305可实现2K鼠标上报率功能,具体功能和实现做以下讲解。描述:需要使用2块CH592的开发板和1块CH305开发板。2块CH592分别作为2.4GMouse(TX)和Dongle(RX)端的无线设备;CH305作为Dongle端连接上位机。连接示意图参考:代码烧录与接线:①烧录:由沁恒官方提供的3份......