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

手机做车载mp3下载网站做自己的网站的一般步骤

手机做车载mp3下载网站,做自己的网站的一般步骤,摄影网站首页设计,手机网站开发需求文档目录 前言: 一、前文补充 二、服务端的修改 三、Command类的新增 前言: 好久不见,最近忙于其他事情,就耽误了咱们的Linux的网络部分的学习。 今天咱们先来给之前所学的TCP的部分进行一个首尾工作,主要是给大家介绍…

目录

 

前言:

一、前文补充

二、服务端的修改

三、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.dtcms.com/a/425014.html

相关文章:

  • 手游网站建设方案预算佛山+客户端官网
  • 沈阳网站关键词聊城网站建设有限公司
  • 湖州城市投资建设集团网站淄博做网站的网络公司
  • 网站由什么组成韩国优秀设计网站
  • samba分配权限————附带详细操作步骤
  • 装饰网站建设公司wordpress简约红主题
  • 江山网站制作龙岗网站建设公司哪家好
  • 全球资本开支激增,就业增长停滞:AI时代的双刃剑
  • 网站建设需求确定彩页设计报价
  • 做国际网站怎么发货网站开发前端学习
  • 一文详解决策树:ID3与C4.5算法
  • 2×2 的幻方(包括非标准幻方)在数学上是不存在的
  • 中法电商网站建设网站建设就业
  • 【Git】远程项目被迁移或重命名,推送失败
  • 涿鹿镇做网站做app和做网站的区别
  • JAVA·顺序逻辑控制
  • 强化学习原理(六)
  • 鹰潭市建设局网站宣传片视频
  • 寻找数组的中心下标
  • 建立网站的链接结构有哪几种形式?西安牛二网络科技有限公司
  • 【完整源码+数据集+部署教程】【智慧工地监控】建筑工地设备分割系统: yolov8-seg-efficientViT
  • 沈阳市建设工程质量监督局网站dede增加手机网站
  • 网站建设项目维护与评价书施工企业主要负责人包括
  • 邯郸网站建设品牌公司苏州建设交通
  • 四大网站wordpress怎样连接数据库连接
  • BMW agent图介绍
  • 空间链接制作网站免费的黄冈网站有哪些平台可以聊天呢
  • IOT_通讯控制器(无线通讯)
  • 百度站长平台工具WordPress建站详细过程
  • git的merge与rebase的区别与操作