当前位置: 首页 > news >正文

wakeonlan-tcp 开发复盘

wakeonlan-tcp 开发复盘

巴法云 TCP 协议的应用实践
项目地址:https://github.com/awalol/bemfa-wol-client

AI 摘要

本文记录了使用 C++20 开发轻量化远程开机工具 wakeonlan-tcp 的全过程。针对嵌入式设备存储空间受限的痛点,通过放弃 Golang 改用原生 C++ 与巴法云 TCP 协议通信,成功将程序体积从数 MB 缩减至 KB 级。文章重点分享了基于 getaddrinfo 的域名解析、利用 RAII 机制(jthread) 管理多线程心跳保活、以及通过“逻辑短路”优化重连逻辑的实践经验。

开发背景

主包有远程桌面的需求 (为了在外面远程串流打游戏) 因此需要远程开机。

这个项目有两个前身:
1.esp32版本,连接到点灯平台(Blinker)远程下发指令。但是主包的ESP32被主包玩坏了 (注意不要像主包那么傻把引脚接反啊!!!)
2.Golang版本,原理跟现在的类似,但是使用的是mqtt协议连接。因为golang本身需要塞个runtime进去,生成出来的体积有5.5MB,使用upx压缩以后还有1.6MB,路由器的flash空间太小只能放在tmp目录,重启就没了

为了熟悉c/c++基础组件的使用,所以这个项目选择了c++进行重写 (以后还有可能再用 rust 进行重写?) 反正都是练手

开发过程

协议的选择

为了尽可能减小程序的体积,所以不引入外部库,只使用c++内部的组件。通过巴法云的手册来看,巴法云可以通过TCP与MQTT两种协议接入。于是选择使用TCP协议(其实主包先是用MQTT写了一个版本,就是直接把Golang那个版本搬了过来,但编译出来的大小有5.4MB,这还不如Go写的版本。)

首先先做的肯定是核心部分 — 服务器通信!

Part1:建立TCP连接

C++的TCP通信是围绕 socket 进行的

首先先要进行初始化:
1.如果使用ip进行连接则使用 sockaddr_in 进行初始化,相关代码如下:

点击查看代码
// 1. 创建 socket
int sock = socket(AF_INET, SOCK_STREAM, 0);// 2. 配置服务端地址
sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);// 将 IP 地址从字符串转换为二进制
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);// 3. 连接服务端
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

2.如果使用域名连接,则需要先解析域名地址,使用 addrinfo 进行初始化,相关代码如下(也是本次使用的方法)

点击查看代码
addrinfo hints{}, *res; // hints 为 getaddrinfo 传入连接信息,res 为查询结果
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
const int status = getaddrinfo("bemfa.com", "8344", &hints, &res);
if (status != 0) { // 错误处理cerr << LOG_PREFIX << "getaddrinfo error: " << gai_strerror(status) << endl;return false;
}sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

之后进行连接

connect(sock, res->ai_addr, res->ai_addrlen)

返回值:
成功:0,失败:-1

注意,无论连接成功与失败都要记得释放 addrinfo,避免内存泄漏

freeaddrinfo(res)

因为程序有重连的需求,所以需要设置超时时间

// 设置超时时间
timeval timeout{timeout.tv_sec = 5
};
setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO, &timeout, sizeof(timeout));

这有个知识点,最初我是使用下面这个代码创建 timeout 变量的

timeval timeout;
timeout.tv_sec = 5; // 秒
timeout.tv_usec = 0; // 微秒

我好奇为什么 tv_usec 必须设置,AI 为我解答:
使用这种初始化方式可能会导致结构体里面成员的数值是随机的,而在 C++中,使用 {} 会对执行值初始化,将里面成员都自动初始化为 0

Part2:使用多线程进行消息处理以及发送心跳包保活

由于巴法云要求,我们需要每隔60s向巴法云发送个心跳包
这里我们使用C++20引入的新特性 - jthread,他对比以前的thread自动帮我们做了一些事,简便了开发的流程

首先先构建消息处理线程

线程函数结构:

  void messageReceiver(const stop_token &stopToken) {// 通过超时时间为 5 秒,避免在 read 阻塞造成重连事件不触发while (!stopToken.stop_requested()) {//其余代码请去仓库查看,这里只给出函数结构}
}

然后直接使用jthread创建线程
注意:创建完线程以后会立即开始

receiverThread = jthread(messageReceiver)

开发中有一点需要注意:read 函数是会阻塞代码执行的,如果有重连事件的一定要设置超时时间

Part3:构建main函数以及重连机制

点击查看代码
int main() {// 从环境变量获取参数初始化while (true) {if (sock == -1 && connectToServer()) {fail = 0;subscribeTopic();// 启动线程receiverThread = jthread(messageReceiver);heartbeatThread = jthread(heartbeat);}this_thread::sleep_for(chrono::seconds(60));}return 0;
}

在这里学到一个知识点:逻辑短路
在这行代码里

if (sock == -1 && connectToServer())

这里使用了 && 与条件,如果说 sock == -1 为 false,那么就不会继续执行 connectToServer 这个函数
若使用的是 || 条件,如 if (A || B) ,如果条件 A 为 true,那么就不会继续去判断 B

结语

这次 wakeonlan-tcp 项目让我更深入了学习C++相关的知识
做项目挺有意思的😋,但拖延症导致我挖了很多坑没填

http://www.zskr.cn/news/164745.html

相关文章:

  • Trace Viewer详解:逐层性能剖析
  • 深度解析:2026成都企业选GEO服务商,本地龙头与全国分支谁更胜一筹? - 奇林智媒GEO
  • Linux | 内核源码学习 - 详解
  • 资深老鸟,经验分享-常见的性能测试面试题(附答案)
  • TimeMixer模型:TensorFlow混合架构尝试
  • WordPress漏洞研究:从核心到插件的安全攻防指南
  • ‌DevOps中的测试稳定性保障:熔断、降级与自愈机制‌
  • Audio Summary插件:语音模型效果可视化
  • day46(12.27)——leetcode面试经典150
  • 12月23号
  • 毕业设计项目 stm32智能鱼缸监控投喂系统(源码+硬件+论文)
  • Kubernetes Operator设计:自动化TensorFlow作业调度
  • 12月26号
  • 对比学习Contrastive Learning框架搭建
  • 电子汽车衡厂家生产企业2025排名榜单 - 栗子测评
  • 温州视频拍摄哪家好?2025温州短视频推广服务口碑榜 - 栗子测评
  • 2025幕墙铝单板厂家定制指南:附上幕墙铝单板厂家联系方式 - 栗子测评
  • 大脑能力32岁才达巅峰!Cell和Nature子刊:一生有4个转折点,32岁正值高效“换挡”期,但内分泌率先失守,开始断崖式衰老
  • Prometheus + Grafana监控TensorFlow GPU指标
  • Sidecar不就是在Pod里多跑一个容器吗!
  • 用WOA-DELM实现回归预测:基于鲸鱼优化算法与深度极限学习机的结合
  • FEDformer频域变换:TensorFlow版本解读
  • TensorFlow Quantum初探:量子机器学习前沿
  • CentralStorageStrategy适用场景与性能对比
  • MXNet停止维护后用户转向TensorFlow趋势观察
  • python基于大数据的老旧小区改造需求评估与分析系统(带大屏)_lo2w4579
  • Memory Timeline分析:优化GPU显存占用
  • python建筑工程项目管理系统设计与实现_95ig3zyt
  • python教学管理自动化系统设计与实现 大学课程课表管理系统_54r67p9b
  • 探索C#运控框架:基于雷赛DMC系列的运动控制项目