Linux网络编程:TCP的远程多线程命令执行
一、前文补充前面我们已经通过多线程多进程线程池的方式分别实现了一个我们的TCP的EchoServer今天我们先借着之前的代码来继续学习。我们之前在进行TCP的数据的读取写入的时候用到的函数是大家之前见过的write与read函数。其实我们这里之所以用到他们主要是为了帮助大家理解我们通过accept返回的文件描述符。但实际上我们的还可以使用另外一套接口来进行数据的传输与传入。首先就是recv这个函数的第一个参数一样是一个文件描述符第二个参数要求我们提供一个用来接收消息的缓冲区第三个参数是这个缓冲区的大小第四个参数咱们先暂时不用管直接填0就可以了。所以我们的read函数就可以变成代码语言javascriptAI代码解释int n ::recv(sockfd,buffer,sizeof(buffer)-1,0);0表示默认行为即阻塞等待消息。这里使用sizeof(buffer)-1一样是为了手动最后添上字符串终止符\0与之对应的在客户端的写入消息就可以使用send代码语言javascriptAI代码解释int n ::send(_sockfd, message.c_str(), message.size(), 0);值得注意的是不管是我们在这里使用read write还是send recv。其都是一个读取/写入不完善的操作。为什么这样说呢可能要到下节序列化我才能详细给大家说明。但是这个不完善是因为TCP的特点。还记得吗TCP是面向字节流UDP是面向数据报。对于我们的UDP来说每次传输数据都是把所有数据传输过去而面向字节流不同。假如我们今天要给你发送一个 hello world那么我们一定会完整接受到hello world吗这是不一定的说不定我们只会先接受到hello。更详细的内容我们会在后面进行讲解。那么下面开始我们的今天的正题如何给我们的服务端添加上执行命令的这些功能。二、服务端的修改首先我们需要明确。在我们的服务端仍然是通过之前写的一个回调函数HandlerRequest来让每一个线程执行。我们想要降低耦合性让这个执行命令的功能不于我们的服务端文件杂糅在一起所以我们可以先另起一个头文件。通过之前的方式创建一个执行命令的对象然后在服务端类初始化时通过lambda表达式传进来一个回调函数。所以我们需要在服务端的类成员变量中新增一个变量用来回调。那我们先规定传进来的lambda表达式的类型。所以我们就先定义一个类型名为代码语言javascriptAI代码解释using handler_tstd::functionstd::string (std::string);随后新增该类型的类成员变量代码语言javascriptAI代码解释TcpServer(handler_t handler ,uint16_t port defaultport) : _port(port), is_running(false), _handler(handler) { } ...... private: handler_t _handler;//回调函数执行命令调用的接口在外界创建的时候就传入一个lambda如同这样代码语言javascriptAI代码解释int main() { Command cmd; std::unique_ptrTcpServer tcp_ptrstd::make_uniqueTcpServer([cmd](std::string cmdstr){ return cmd.Execute(cmdstr); }); tcp_ptr-InitServer(); tcp_ptr-Start(); return 0; }这个方法之前我们已经使用过很多次了。所以这里就加快速度。那么要继续实现的就是我们的这个Command类的成员方法了如何实现呢三、Command类的新增现在我们开始实现一下我们的Command类首先就是类成员变量我们可以设置一个白名单或者黑名单就是限制一下那些命令我们可以使用哪些命令我们不能使用。我们这里就使用白名单的思维在成员变量中实用set只要在我们的set里就是可以使用的。随后在我们的构造函数中添加一下可以使用的命令集并增加一个判断是否在我们的白名单的bool函数SafeCheck:代码语言javascriptAI代码解释#pragma once #includestring #include set class Command { public: Command() { _white_list.insert(ls); _white_list.insert(pwd); _white_list.insert(ls -l); _white_list.insert(ll); _white_list.insert(touch); _white_list.insert(who); _white_list.insert(whoami); } bool SafeCheck(const std::string cmdstr) { auto iter _white_list.find(cmdstr); return iter _white_list.end() ? false : true; } std::string Execute(std::string cmdstr) { } private: std::setstd::string _white_list; };这样我们只需要在实现一下我们的执行命令的函数。那么我们怎么执行呢我们之前是不是写过SHell把我们之前写SHell的逻辑拿过来可以吗肯定是可以的。但是我们都学了这么久了还使用我们之前的方法未免不是很好今天给大家介绍两个函数代码语言javascriptAI代码解释popen 函数 FILE *popen(const char *command, const char *mode);这个popen函数他是什么功能呢创建一个管道fork一个子进程并调用shell执行指定的命令他有两个参数第一个参数就是传进去的命令字符串第二个参数就是模式r表示从命令的 标准输出 读取数据若为w则可向命令的标准输入写入。没错这个功能直接把我们以前所需要的做的工作全部都做了集成到了这一个函数里。他会返回一个文件流指针我们可以通过这个文件流指针读取信息。具体操作如下代码语言javascriptAI代码解释if (!SafeCheck(cmdstr)) { return std::string(cmdstr 不支持); } FILE *fp ::popen(cmdstr.c_str(), r); if (nullptr fp) { return std::string(Failed); } char buffer[1024]; std::string result; while (true) { char *ret ::fgets(buffer, sizeof(buffer), fp); if (!ret) break; result ret; }像我们输入什么whoani这种命令都是有个打印效果的我们此时就能通过fgets来获取并返回。最后与之对应的我们会有pclose这个函数负责关闭这个管道流并等待子进程结束。代码语言javascriptAI代码解释#pragma once #includestring #include set class Command { public: Command() { _white_list.insert(ls); _white_list.insert(pwd); _white_list.insert(ls -l); _white_list.insert(ll); _white_list.insert(touch); _white_list.insert(who); _white_list.insert(whoami); } bool SafeCheck(const std::string cmdstr) { auto iter _white_list.find(cmdstr); return iter _white_list.end() ? false : true; } std::string Execute(std::string cmdstr) { if (!SafeCheck(cmdstr)) { return std::string(cmdstr 不支持); } FILE *fp ::popen(cmdstr.c_str(), r); if (nullptr fp) { return std::string(Failed); } char buffer[1024]; std::string result; while (true) { char *ret ::fgets(buffer, sizeof(buffer), fp); if (!ret) break; result ret; } pclose(fp); return result.empty() ? std::string(Done) : result; } private: std::setstd::string _white_list; };注意我们还要在服务端类中手动调用回调函数并获取返回值代码语言javascriptint n ::recv(sockfd, buffer, sizeof(buffer) - 1, 0); if (n 0) { buffer[n] 0; // 手动置入一个结束标记 // std::string echo_str server echo$; // echo_str buffer; std::string cmd_result _handler(buffer); ::send(sockfd, cmd_result.c_str(), cmd_result.size(), 0); }最后我们编译运行

相关新闻

为什么你的C++23项目必须升级到C++27契约语法?——基于Linux内核模块与自动驾驶中间件的实测性能对比报告

为什么你的C++23项目必须升级到C++27契约语法?——基于Linux内核模块与自动驾驶中间件的实测性能对比报告

第一章:C27契约编程安全校验的演进动因与标准定位C27将首次正式纳入契约(Contracts)作为核心语言特性,其设计并非对C20实验性契约提案的简单延续,而是基于工业级安全关键系统对可验证程序行为的迫切需求。近年来&#…

2026/5/17 11:14:48 阅读更多 →
C++ 核心知识点汇总(第三日)(分支结构)

C++ 核心知识点汇总(第三日)(分支结构)

C 核心知识点汇总(第三日)——分支结构(if / switch / 三元运算符) 2026最新版 零基础到进阶全覆盖 今天我们进入C程序控制流的核心篇——分支结构。 掌握分支结构后,你就能写出真正的“会判断、会选择”的程序&…

2026/5/17 11:14:46 阅读更多 →
Python窗体编程技术详解

Python窗体编程技术详解

【Python窗体编程技术详解】——从入门到进阶(2026最新版) 🖥️ 大家好!Python窗体编程(GUI编程)是Python开发者进阶必备技能。它能让你从命令行脚本走向可视化应用,如桌面工具、数据可视化、游…

2026/7/4 9:10:09 阅读更多 →

最新新闻

Rust async Drop 难题:资源释放不要藏在未来某个 await 后面

Rust async Drop 难题:资源释放不要藏在未来某个 await 后面

Rust async Drop 难题:资源释放不要藏在未来某个 await 后面 一、Drop 是同步的 Rust 的 Drop trait 是同步执行的,不能直接 await。这在普通资源释放里问题不大,但在异步系统里会变复杂:关闭网络连接、刷盘、通知远端、释放推理会…

2026/7/5 1:56:29 阅读更多 →
Redis Stream 消息队列总结

Redis Stream 消息队列总结

1. Stream 是什么Redis Stream 是 Redis 提供的一种消息队列数据结构,用于保存和传递一系列消息。它的核心特点是:消息有唯一 ID。消息会持久化保存在 Redis 中,不会像 Pub/Sub 一样发送后立刻丢失。支持消费者组。支持消息确认机制。支持查看…

2026/7/5 1:52:27 阅读更多 →
【大白话说Java面试题 第153题】【06_Spring篇】第13题:Spring 中 Bean 是线程安全的吗?

【大白话说Java面试题 第153题】【06_Spring篇】第13题:Spring 中 Bean 是线程安全的吗?

📌 PDF:大白话说Java面试题 — 06_Spring篇 第13题:Spring 中 Bean 是线程安全的吗? 📚 回答: 核心考点: Spring Bean 的线程安全性是并发编程与 Spring 框架交叉的经典问题,大厂面…

2026/7/5 1:50:25 阅读更多 →
Java计算机毕设之美容会员储值充值积分管理系统的设计与实现 美业技师业绩提成统计管理系统(完整前后端代码+说明文档+LW,调试定制等)

Java计算机毕设之美容会员储值充值积分管理系统的设计与实现 美业技师业绩提成统计管理系统(完整前后端代码+说明文档+LW,调试定制等)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/5 1:48:25 阅读更多 →
电容式触摸按键 PCB 设计 10 要点:从 PAD 形状到走线间距的实战避坑

电容式触摸按键 PCB 设计 10 要点:从 PAD 形状到走线间距的实战避坑

电容式触摸按键PCB设计10大核心要点:从焊盘优化到抗干扰布局实战指南在智能家电和消费电子领域,电容式触摸按键正在快速取代传统机械按键。根据行业调研数据,2022年全球电容式触摸控制器市场规模已达12.7亿美元,年复合增长率保持在…

2026/7/5 1:46:23 阅读更多 →
校友质量高的国内EMBA 2026综合实力权威榜单

校友质量高的国内EMBA 2026综合实力权威榜单

一、榜单评测引言随着国内企业全球化布局、数字化转型进程加速,越来越多企业创始人、高层管理者摒弃传统单一管理进修模式,优先选择校友圈层优质、国际化资源充足、学历认可度高的中英双语EMBA项目。优质校友圈层不仅是职场进阶、企业发展的核心人脉资源…

2026/7/5 1:44:23 阅读更多 →

日新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻