目录

 

前言:

一、前文补充

二、服务端的修改

三、Command类的新增


 

前言:

好久不见,最近忙于其他事情,就耽误了咱们的Linux的网络部分的学习。

今天咱们先来给之前所学的TCP的部分进行一个首尾工作,主要是给大家介绍一些函数与补充一下知识点。

那么今天我们将要实现的这个将会是什么功能呢?我们预期的就是大家远程通过客户端连接上服务端后,可以在服务端输入一些命令,让我们的服务端进行执行。

一、前文补充

前面我们已经通过多线程,多进程,线程池的方式分别实现了一个我们的TCP的EchoServer,今天我们先借着之前的代码来继续学习。

我们之前在进行TCP的数据的读取写入的时候,用到的函数是大家之前见过的write与read函数。其实我们这里之所以用到他们,主要是为了帮助大家理解我们通过accept返回的文件描述符。

但实际上我们的还可以使用另外一套接口,来进行数据的传输与传入。

首先就是recv:

这个函数的第一个参数一样是一个文件描述符,第二个参数要求我们提供一个用来接收消息的缓冲区,第三个参数是这个缓冲区的大小,第四个参数咱们先暂时不用管,直接填0就可以了。

所以我们的read函数就可以变成:

 int n = ::recv(sockfd,buffer,sizeof(buffer)-1,0);

0表示默认行为,即阻塞等待消息。这里使用sizeof(buffer)-1一样是为了手动最后添上字符串终止符 \0

与之对应的,在客户端的写入消息,就可以使用send:

 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表达式的类型。

所以我们就先定义一个类型名为:

using handler_t=std::function<std::string (std::string)>;

随后新增该类型的类成员变量:

 TcpServer(handler_t handler ,uint16_t port = defaultport): _port(port),is_running(false),_handler(handler){}......private:handler_t _handler;//回调函数执行命令调用的接口

在外界创建的时候就传入一个lambda,如同这样:


int main()
{Command cmd;std::unique_ptr<TcpServer> tcp_ptr=std::make_unique<TcpServer>([&cmd](std::string cmdstr){return cmd.Execute(cmdstr);});tcp_ptr->InitServer();tcp_ptr->Start();return 0;
}

这个方法之前我们已经使用过很多次了。所以这里就加快速度。

那么要继续实现的就是我们的这个Command类的成员方法了,如何实现呢?

三、Command类的新增

现在我们开始实现一下我们的Command类:

首先就是类成员变量,我们可以设置一个白名单或者黑名单,就是限制一下那些命令我们可以使用,哪些命令我们不能使用。

我们这里就使用白名单的思维,在成员变量中实用set,只要在我们的set里,就是可以使用的。

随后,在我们的构造函数中,添加一下可以使用的命令集,并增加一个判断是否在我们的白名单的bool函数SafeCheck:

#pragma once
#include<string>
#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::set<std::string> _white_list;
};

这样我们只需要在实现一下我们的执行命令的函数。

那么我们怎么执行呢?

我们之前是不是写过SHell,把我们之前写SHell的逻辑拿过来可以吗?

肯定是可以的。但是我们都学了这么久了,还使用我们之前的方法未免不是很好,今天给大家介绍两个函数:

popen 函数FILE *popen(const char *command, const char *mode);

这个popen函数他是什么功能呢?

:创建一个管道,fork一个子进程,并调用shell执行指定的命令

他有两个参数,第一个参数就是传进去的命令字符串,第二个参数就是模式,"r"表示从命令的 标准输出 读取数据,若为 "w" 则可向命令的标准输入写入。

没错,这个功能直接把我们以前所需要的做的工作全部都做了,集成到了这一个函数里。

他会返回一个文件流指针,我们可以通过这个文件流指针读取信息。

具体操作如下:

        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这个函数,负责关闭这个管道流,并等待子进程结束。

#pragma once
#include<string>
#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::set<std::string> _white_list;
};

注意,我们还要在服务端类中手动调用回调函数并获取返回值:

         int 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);}

最后我们编译运行:

 

 

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

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

相关文章

重学React(三):状态管理

背景&#xff1a; 继续跟着官网的流程往后学&#xff0c;之前已经整理了描述UI以及添加交互两个模块&#xff0c;总体来说还是收获不小的&#xff0c;至少我一个表面上用了四五年React的前端小卡拉米对React的使用都有了新的认知。接下来就到了状态管理&#xff08;React特地加…

java web项目入门了解

目录一、项目流程1. 使用servle2. 使用框架二、了解java web项目构造1. 项目目录结构2. 查看页面访问顺序3. 发起请求&#xff1a;jqueryajax4. 接受参数5. JSONJSON 数组三、get和post请求区别一、项目流程 1. 使用servle 有客户端和服务端&#xff0c;客户端和服务端进行交…

网络资源模板--基于Android Studio 实现的日记本App

目录 一、测试环境说明 二、项目简介 三、项目演示 四、部设计详情&#xff08;部分) 创建修改页面 五、项目源码 一、测试环境说明 电脑环境 Windows 11 编写语言 JAVA 开发软件 Android Studio (2020) 开发软件只要大于等于测试版本即可(近几年官网直接下载也可…

GO的启动流程(GMP模型/内存)

目录第一部分&#xff1a;程序编译第二部分&#xff1a;函数解读1&#xff09;Golang 核心初始化过程2&#xff09;创建第一个协程3&#xff09;启动系统调度4&#xff09;跳转main函数5&#xff09;总结第三部分&#xff1a;GMP模型Goroutine流程解读第四部分&#xff1a;内存…

OLTP与OLAP:实时处理与深度分析的较量

OLTP&#xff08;Online Transaction Processing&#xff09;定义&#xff1a;OLTP 系统主要用于管理事务性应用程序的数据。这类系统需要支持大量的短时、快速的交互式事务&#xff0c;比如银行交易、在线购物订单等。特点&#xff1a;实时处理&#xff1a;OLTP 系统要求对数据…

数据安全与隐私保护:企业级防护策略与技术实现

引言&#xff1a;数据安全的新时代挑战在数字化转型加速的今天&#xff0c;数据已成为企业最核心的资产。然而&#xff0c;数据泄露事件频发&#xff0c;据 IBM《2024 年数据泄露成本报告》显示&#xff0c;全球数据泄露平均成本已达445 万美元&#xff0c;较 2020 年增长了 15…

AI_RAG

一.为什么需要RAG&#xff08;AI幻觉&#xff09;大模型LLM在某些情况下给出的回答很可能错误的&#xff0c;涉及虚构甚至是故意欺骗的信息。二.什么是RAGRAG是一种结合“信息检索”和“文本生成”的技术&#xff0c;旨在提升生成式AI模型的准确性和可靠性。它通过以下两个核心…

LeetCode111~130题解

LeetCode111.二叉树的最小深度&#xff1a; 题目描述&#xff1a; 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明&#xff1a;叶子节点是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root …

n8n飞书webhook配置(飞书机器人、飞书bot、feishu bot)Crypto节点、js timestamp代码、Crypto node

自定义机器人使用指南 利用 n8n 打造飞书 RSS 推送机器人 文章目录自定义机器人使用指南注意事项功能介绍在群组中添加自定义机器人操作步骤邀请自定义机器人进群。- 进入目标群组&#xff0c;在群组右上角点击更多按钮&#xff0c;并点击 设置。- 在右侧 设置 界面&#xff0…

nhdeep档案管理工具软件官网

欢迎访问nhdeep官网&#xff1a; www.nhdeep.com NHDEEP提供一系列专业的单机版档案管理工具&#xff0c;满足不同场景下的档案管理需求&#xff0c;无需网络连接&#xff0c;数据安全可靠。所有工具均提供免费试用版下载。 档案综合管理系统单机版:全面的档案管理解决方案&a…

RocketMQ节点部署计算方案

节点计算公式 业务场景 预期峰值TPS&#xff1a;200,000 单组容量&#xff1a;40K TPS 容灾要求&#xff1a;同城双机房 nameServer节点数max(3, (15/50) 1) max(3, 0.3 1) max(3, 1.3) 3 Broker节点数ceil(200,000 / 40,000) 5组 总节点数 NameServer节点Broker组数(Mas…

MyBatis联合查询 - XML篇

文章目录数据库设计MyBatis 配置MyBatis 映射文件Mapper 接口总结数据库设计 建表 SQL CREATE TABLE user (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50) NOT NULL );CREATE TABLE order (id INT PRIMARY KEY AUTO_INCREMENT,user_id INT NOT NULL,order_no VARCHAR(…

Kubelet 探针如何选择 IP:status.PodIP 溯源与“同 Pod 两个 IP“现象解析

背景与现象同一个 Pod 的 readiness 和 liveness 探针日志显示连接的 IP 不一致&#xff08;例如 10.10.6.10:9999 与 10.10.6.32:9999&#xff09;。本文从 kubelet 源码入手&#xff0c;解释探针目标 IP 的来源、为何会出现两个不同 IP&#xff0c;并给出建议与验证方法。在如…

Arm Development Studio 安全通告:CVE-2025-7427

安全之安全(security)博客目录导读 目录 一、概述 二、CVE 详情 三、受影响产品 四、建议 五、致谢 六、版本历史 一、概述 ARM已知悉一个影响 Arm Development Studio 的安全漏洞&#xff0c;该漏洞可能允许攻击者执行 DLL 劫持攻击&#xff08;DLL hijacking attack&…

C#异步编程双利器:异步Lambda与BackgroundWorker实战解析

**摘要&#xff1a;**深入剖析两种异步编程范式&#xff0c;解决GUI线程阻塞难题 一、异步Lambda表达式&#xff1a;事件处理的轻量化利器 核心价值&#xff1a;简化事件响应中的异步操作&#xff0c;避免UI线程阻塞 ✅ 典型应用场景&#xff08;WPF示例&#xff09;&#xff1…

yolo world (1): 论文解读

YOLO 系列检测器以其高效性和实用性而闻名。然而,它们依赖于预定义和训练的目标类别,这限制了其在开放场景中的适用性。为了解决这一限制,我们提出了 YOLO-World,这是一种创新的方法,通过视觉-语言建模和大规模数据集预训练,增强了 YOLO 的开放词汇检测能力。具体来说,我…

【JVM】深入解析Java虚拟机

目录 1. 区分JDK&#xff0c;JRE 和 JVM 1.1 JVM 1.2 JRE 1.3 JDK 1.4 关系总结 2. 跨平台性 3. JVM中的内存划分 4. JVM的类加载机制 5. 双亲委派模型 6. 垃圾回收机制&#xff08;GC&#xff09; 6.1 识别垃圾 6.1.1 单个引用 6.1.2 多个引用 6.2 释放垃圾 6.…

98-基于Python的网上厨房美食推荐系统

基于Python的网上厨房美食推荐系统 - 技术分享博客 &#x1f4cb; 目录 项目概述技术栈系统架构核心功能实现数据库设计推荐算法数据可视化部署与优化项目特色总结与展望 &#x1f3af; 项目概述 项目背景 随着生活节奏的加快&#xff0c;越来越多的人开始关注美食制作&…

创建MyBatis-Plus版的后端查询项目

记得编码和maven库的检测&#xff01;&#xff01;&#xff01; 1、maven库导入包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupI…

开发板RK3568和stm32的异同:

RK3568 和 STM32 是两类不同定位的处理器 / 微控制器&#xff0c;在架构、性能、应用场景等方面差异显著&#xff0c;但也存在部分共性。以下从核心特性、异同点及典型场景进行对比&#xff1a;一、核心差异维度RK3568&#xff08;瑞芯微&#xff09;STM32&#xff08;意法半导…