【计算机网络】网络版本计算器
此前我们关于TCP协议一直写的都是直接recv或者read,有了字节流的概念后,我们知道这样直接读可能会出错,所以我们如何进行分割完整报文?这就需要报头来解决了!
但当前我们先不谈这个话题,先从头开始。
将会着重理解OSI
7层模型中传输层向上的3层,并编码进行解释。
而恰好tcp/ip模型是4层(或5层),将OSI上三层统一压缩为1层应用层了,这究竟又有什么关系呢?
我们实际编程中也正是按照这种模式进行编写的。
目录
- 1. 服务端
- 1.1 会话层
- 1.2 表示层
- 1.3 应用层
- 2. 客户端
- 2.1表示层
- 3. 完整代码:
1. 服务端
1.1 会话层
会话层是一个什么意思?
通俗理解就是建立连接与断开连接,也就是connect与accept
我们都是在server的hpp文件中进行的:
下段代码是一个大概的流程,这也就是编码实现会话层
int fd = accept...IO_service(fd等需要的参数...)close(fd)
1.2 表示层
这段话确实抽象
通俗理解就是:两个通信的主机按照一定的格式进行传输信息:即按照相同的请求协议与响应协议进行转化(序列化和反序列化)传输数据。
在之前的基于tcp的网络服务程序中,我们表面没有体现出这个,但实际上我们传输的协议就是传输字符串,这也是我们约定好的。
这层也是我们今天的重点。
由于我们当前是基于结构体传输(请求协议与响应协议),但是由于技术原因与业务原因导致直接使用结构体传输会导致各种各样的问题,所以我们序列化为固定格式的字符串进行传输,在反序列为你需要的协议格式进行操作。这是我们在应用层自定义协议就已经说过的了。
但因为是字节流的原因,所以recv或read到的字符串不一定是完整的请求,因此需要添加报头
进行解决。
我们先来解决序列化与反序列化的问题。
其中序列化我们可以手写,也可以借助各种各样的库文件进行操作,这里我们选择使用json,最主要的原因还是因为可视化:
关于json我们可以大概的了解一下,熟悉一下接口即可。
class Request
{
public:Request(int x, int y, char oper): _x(x),_y(y),_oper(oper){}Request(){}void Serialization(std::string *out){Json::Value root;root["x"] = _x;root["y"] = _y;root["oper"] = _oper;Json::StyledWriter writer;// Json::FastWriter writer;*out = writer.write(root);}void Deserialization(const std::string &in){Json::Reader reader;Json::Value root;reader.parse(in, root);_x = root["x"].asInt();_y = root["y"].asInt();_oper = root["oper"].asInt();}void Print(){std::cout << _x << std::endl;std::cout << _y << std::endl;std::cout << _oper << std::endl;}~Request(){}public:int _x;int _y;int _oper;
};int main()
{Request req(1, 1, '*');std::string str;req.Serialization(&str);std::cout << str << std::endl;Request req1;req.Deserialization(str);req.Print();return 0;
}
注意由于json是第三方库,记得编译时-ljsoncpp
验证:
尽管我们现在是在进行序列化与反序列化,但是在序列化与反序列化前总得有请求请求协议与响应协议吧。
class Request
{
public:Request(int x, int y, char oper): _x(x),_y(y),_oper(oper){}Request(){}~Request(){}public:int _x;int _y;int _oper;
};class Response
{
public:Response(): _code(0),_desc("sucess"){}~Response(){}public:int _result;int _code; // 0:sucess, 1:div zero, 2:mod zero, 3:invalid operstd::string _desc;
};
上段代码就是两个协议的基本内容。
因此我们现在即可构建请求协议与响应协议的序列化与反序列化,没错,每种协议都需要构建序列化与反序列化:
当客户端构建数据构需要序列化再传输,服务端接收后再反序列化;
服务端处理完数据后再将响应协议对象序列化传输,客户端再反序列化得到结果。
这张图就很形象的展示了过程。
但是我们还需要解决如何获得的是一个完整的请求的问题,我们已经说过解决方案了,那就是添加报头,于是我们进一步完善协议。
那么添加的报头是怎样的格式?
"len"\r\n{json串}\r\n
这种形式是非常通用的,我们在HTTP协议中也可以看到这种形式的影子。
现在解释一下参数
len就是json串的长度,\r\n本质上就是换行,这样的健壮性更强(\r是回退到初始行,\n换行,但现在我们的\n基本上都包含了换行到新行的开头的功能了。)
现在解释一下为什么这么做:
// "le --> 残缺报文
// "len"\r\n{json} --> 残缺报文
// "len"\r\n{json}\r\n --> 完整报文
// "len"\r\n{json}\r\n"len"\r\n{jso --> 冗余报文
// "len"\r\n{json}\r\n"len"\r\n{json}\r\n"len"\r\n{json}\r\n --> 冗余报文
因为面向字节流,所以我们有可能得到的数据是以上样子,当我们这样设计报头时,不论何种情况都可以处理。
假设是第一种情况:我们先find \r\n,若是没有则说明当前是不完整的报文,继续recv即可。
若是第二种:我们由于find到了\r\b,所以就可得知json串的具体长度,根据具体长度得到是否为完整的报文。
若是第四/五种:我们直接截取最前方的完整报文即可。
故此时我们即可设计添加报头。
// 添加报头
std::string sep = "\r\n";std::string EnHeader(const std::string &packagestream)
{int len = packagestream.size();std::string ret = std::to_string(len);return ret + sep + packagestream + sep;
}// 注意这里我们传参是非const,原因在于当得到不完整报文返回时,还能续接。(具体可以在完整代码中体现)
std::string DeHeader(std::string &packagestream)
{// 还没有读到lenauto pos = packagestream.find(sep);if (pos == std::string::npos){return {}; }// 检查是否为一个完整的json串int len = std::stoi(packagestream.substr(0, pos));int total = pos + len + 2 * sep.size();if (total > packagestream.size()){return {};}// 至少有一个完整的json串std::string ret = packagestream.substr(pos + sep.size(), len);packagestream = packagestream.erase(0, total);return ret;
}
如此准备工作便都做好了。
可以进行传输与接收了。
while (true)
{int n = socket->Recv(&messagequeue);if (n <= 0){break;}// 2. 去报头std::string ret = DeHeader(messagequeue);if (ret.size() == 0){continue;}// 3. 一个完整的报文,进行反序列化// 只是利用工厂模式造了一个请求协议智能指针,无需重点关注,重点是进行序列化std::shared_ptr<Request> req = Bulider::GetReq();req->Deserialization(ret);// 4. 执行业务std::shared_ptr<Response> resp = _func(req);// 5. 序列化std::string jsonmessage;resp->Serialization(&jsonmessage);// 6. 添加报头jsonmessage = EnHeader(jsonmessage);// 7. 发送数据n = socket->Send(jsonmessage);if (n < 0){break;}
}
1.3 应用层
应用层就是处理我们的业务的,
我们上段代码的第四步就是应用层。
这里根据我们制作的网络计算机设计对应的业务即可。
class Calculator
{
public:Calculator(){}std::shared_ptr<Response> calculate(std::shared_ptr<Request> req){std::shared_ptr<Response> resp = std::make_shared<Response>();std::cout << req->_x << req->_oper << req->_y << std::endl;switch (req->_oper){case '+':resp->_result = req->_x + req->_y;break;case '-':resp->_result = req->_x - req->_y;break;case '*':resp->_result = req->_x * req->_y;break;case '/':{if (req->_y == 0){resp->_code = 1;resp->_desc = "div zero";}else{resp->_result = req->_x / req->_y;}}break;case '%':{if (req->_y == 0){resp->_code = 2;resp->_desc = "mod zero";}else{resp->_result = req->_x % req->_y;}}break;default:{resp->_code = 3;resp->_desc = "illegal operation";}break;}return resp;}~Calculator(){}
};
最后将3层整合在一起即可,这些便都是套路了,在完整代码中即可看到。
2. 客户端
本质上与服务端是很相似的,只是那几个步骤变了变顺序而已。
2.1表示层
while (true)
{// 构建数据std::shared_ptr<Request> req = Bulider::GetReq();req->_x = rand() % 10;req->_y = rand() % 10;req->_oper = oper[req->_y % oper.size()];// 序列化数据std::string reqstr;req->Serialization(&reqstr);// 添加报头reqstr = EnHeader(reqstr);// 发送数据int n = sockclient->Send(reqstr);// 接收数据std::string recvstr;while (true){n = sockclient->Recv(&recvmessage);if (n < 0){break;}// 去报头recvstr = DeHeader(recvmessage);if (recvstr.size() == 0){continue;}break;}// 反序列化std::shared_ptr<Response> resp = Bulider::GetResp();resp->Deserialization(recvstr);
}
3. 完整代码:
Gitee代码展示。
完~
相关文章:
![](https://i-blog.csdnimg.cn/direct/e5e9665bc5db4baeb05b18efd0c575e2.png)
【计算机网络】网络版本计算器
此前我们关于TCP协议一直写的都是直接recv或者read,有了字节流的概念后,我们知道这样直接读可能会出错,所以我们如何进行分割完整报文?这就需要报头来解决了! 但当前我们先不谈这个话题,先从头开始。 将会…...
![](https://img-blog.csdnimg.cn/img_convert/bae360c87763395fd38807ed213dc466.png)
使用 Python 爬虫进行网站流量分析:Referer 头的利用
在互联网时代,网站流量分析是了解用户行为、优化网站结构和提升用户体验的重要手段。本文将介绍如何使用 Python 爬虫技术结合 HTTP Referer 头进行网站流量分析,以及如何实现这一过程。 什么是 HTTP Referer 头? HTTP Referer 头是一个请求…...
![](https://www.ngui.cc/images/no-images.jpg)
梧桐数据库(WuTongDB):数据库技术中LL算法详解
LL 算法是一种自顶向下的语法分析算法,广泛用于构建解析器。LL 分析器逐个读取输入符号,从左到右分析(Left-to-Right),并使用最左推导(Leftmost Derivation)来生成语法树。因此,LL 分…...
![](https://img-blog.csdnimg.cn/img_convert/1aa7d7a78793007c38310179b3887551.jpeg)
【秋招笔试】8.18大疆秋招(第一套)-后端岗
🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 编程一对一辅导 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🍒 本专栏已收…...
![](https://www.ngui.cc/images/no-images.jpg)
CSS 的text-size-adjust属性
text-size-adjust 属性在CSS中用于控制用户是否可以调整网页中文字的字体大小。这个属性主要针对移动设备上的浏览器,尤其是那些允许用户通过捏合(pinch)手势来缩放整个页面的浏览器。 语法 text-size-adjust: none; text-size-adjust: aut…...
![](https://i-blog.csdnimg.cn/direct/7c7c110fa2cb403ba21db81e89f2c01f.png)
阿里MAXCOMPUTE数据专辑信息读取并同步数据表
阿里MAXCOMPUTE数据专辑信息读取并同步数据表 在阿里云大数据体系中,我们可以使用数据地图的数据专辑,对数据的类别等进行一个管理 那么管理后的数据,我们想要落表进行相关的数据分析,如何做呢? 查看阿里云官方文档…...
![](https://img-blog.csdnimg.cn/330a8744c54347028f04a91c5b656f70.jpg)
rufus制作ubantu的U盘安装介质时,rufus界面上的分区类型选什么?
rufus制作ubantu的U盘安装介质时,rufus软件界面上的分区类型选什么(如下图)? 在使用Rufus制作Ubuntu的U盘安装介质时,分区类型的选择取决于我们的计算机的引导方式。 以下是具体的选择建议: 1、查看计算机的引导方式…...
![](https://i-blog.csdnimg.cn/direct/4897df638ed34bc7862bcab5b8b25c46.png)
【系统架构设计师-2018年】案例分析-答案及详解
试题一(25分) 阅读以下关于软件系统设计的叙述,在答题纸上回答问题1至问题3。 【说明】 某文化产业集团委托软件公司开发一套文化用品商城系统,业务涉及文化用品销售、定制、竞拍和点评等板块,以提升商城的信息化建设…...
![](https://www.ngui.cc/images/no-images.jpg)
linux驱动入门实验班——平台总线设备驱动模型和设备树
目录 前言 一、重要结构体 二、编程思路 1.platform_driver结构体 2.probe 三、使用设备树 1.步进电机 2.红外遥控 四、代码示例 前言 在这里主要记录学习韦东山老师Linux驱动人入门实验班的笔记,韦东山老师的驱动课程讲的非常好,想要学习驱动…...
![](https://i-blog.csdnimg.cn/direct/fe57e10861154bd6a3c9a85fd2f7c5e4.png)
零基础学习Python(六)
1. 元类的应用 使用元类给对象添加一个固有属性author: 对类名进行限定,要求类名必须是大写字母开头: class MetaC(type):def __init__(cls, name, bases, attrs):if not name.istitle():raise TypeError("类名必须是大写字母开头~")return …...
![](https://i-blog.csdnimg.cn/direct/4f0a4e7f9818450b8086f2d2eaf12652.png)
微信小程序--31(todolist案例)
一.功能 输入待办事件添加代办事件删除代办事件 二、步骤 1.添加输入框 .wxml代码: <!-- 1.输入框 --><input type"text" bindinput"handleInput" value"{{text}}" /> .wxss代码: /* 1.输入框样式 */ i…...
![](https://www.ngui.cc/images/no-images.jpg)
springboot项目使用本地依赖项,打包后出现NoClassDefFoundError的一种解决方法
可以把本地依赖项上传到本地仓库后再引用 建立 Maven 本地仓库并将依赖上传到本地仓库 要建立 Maven 本地仓库并将依赖上传到本地仓库,可以按照以下步骤进行操作: 1. 配置 Maven 本地仓库路径 Maven 默认会在用户的主目录下的 .m2/repository 目录创…...
![](https://i-blog.csdnimg.cn/direct/e06906ab2ca54709af069126f719013a.png)
Maven高级使用指南
在开发大型项目时,Maven作为一个强大的构建和项目管理工具,能显著提升项目管理和构建的效率。然而,随着项目的扩大,维护和管理的复杂性也随之增加。本文将探讨一些高级的Maven用法和解决方案,以帮助你更好地管理大型项…...
![](https://www.ngui.cc/images/no-images.jpg)
windows docker 执行apt-get 权限问题
今天在windows下安装的docker 部署的容器执行apt-get遇到权限问题 PS C:\Users\xiaok> docker exec -it jenkins sh $ apt-get update Reading package lists... Done E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied) E: Unable to l…...
![](https://i-blog.csdnimg.cn/direct/eb234bf41cab42d280aa018de046f389.png)
Linux系统信息排查
目录 介绍步骤 介绍 1、熟悉查看CPU信息、操作系统信息、用户信息、特殊权限账户、启动项和任务计划的排查命令 2、在进行受害主机排查时,首先要对主机系统进行基本排查,方便对受害主机有一个初步的了解。 3、利用lscpu和uname -a查看系统硬件软件基本…...
![](https://i-blog.csdnimg.cn/direct/40a2047893e94721b506f7a08debbfc5.png#pic_center)
《图解设计模式》笔记(四)分开考虑
九、Bridge模式:将类的功能层次结构与实现层次结构分离 类的两个层次结构和作用 类的功能层次结构:希望增加新功能时 父类有基本功能,在子类中增加新功能 Something父类 …├─SomethingGood子类 想要再增加新功能 Something父类 …├─So…...
![](https://i-blog.csdnimg.cn/direct/cafeffc5ee714758847449eff98c84ec.png)
Linux shell编程学习笔记74:sed命令——沧海横流任我行(中)
0 前言 自 60 年代末以来,sed 一直是 Unix 标准工具箱的一部分。 Sed在以下三种情况下特别有用: 编辑太大的文件,无法进行舒适的交互式编辑; 当编辑命令序列过于复杂而无法在交互模式下轻松键入时,可以编辑任何大小的…...
![](https://i-blog.csdnimg.cn/direct/12e6ea3d3b5d4d40841e7ff50d64a81e.png)
[数据集][目标检测]道路积水检测数据集VOC+YOLO格式2699张1类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2699 标注数量(xml文件个数):2699 标注数量(txt文件个数):2699 标注…...
![](https://i-blog.csdnimg.cn/direct/850fb0c4d66c4abab08e4c503076e5d5.png)
不同路径
不同路径 思路: 法一:动态规划 const int N 110; class Solution { int dp[N][N];//dp[i][j]:从起点走到 i j的路径个数。 public:int uniquePaths(int m, int n) {for(int i1;i<n;i){dp[1][i]1;} for(int i1;i<m;i) dp[i][1]1;f…...
![](https://i-blog.csdnimg.cn/direct/a4976a55e43a450a97c0ed1a951b5119.png)
【HTML】HTML学习之引入CSS样式表
1、CSS样式规则 选择器{属性1:属性值1; 属性2:属性值2; 属性3:属性值3;}2、HTML引入CSS样式表 2.1、行内式 行内式也称为内联样式,是通过标签的style属性来设置元素的样式,其基本语法格式如下: <标签名 style"属性1:属性值1; 属性2:属性值2;…...
![](https://i-blog.csdnimg.cn/direct/bce85b848a5f4bb599967df2f2a20e48.png)
shaushaushau1
CVE-2023-7130 靶标介绍: College Notes Gallery 2.0 允许通过“/notes/login.php”中的参数‘user’进行 SQL 注入。利用这个问题可能会使攻击者有机会破坏应用程序,访问或修改数据. 已经告诉你在哪里存在sql注入了,一般上来应该先目录扫…...
![](https://img-blog.csdnimg.cn/direct/cd137335378c45e4a7300d4c8953cf95.png)
揭秘面试必备:高频算法与面试题全面解析
干货分享,感谢您的阅读! (暂存篇---后续会删除,完整版和持续更新见高频面试题基本总结回顾(含笔试高频算法整理)) 备注:引用请标注出处,同时存在的问题请在相关博客留言…...
![](https://www.ngui.cc/images/no-images.jpg)
设计模式-visit模式-在语法树的实践
文章目录 背景示例代码分析灵活性双重分派 总结 背景 很多项目代码有accept()用法,在calcite 里也看到了这种,深入了解一下 语法树遍历:编译器通常会将源代码解析成抽象语法树(AST)。为了实现不同的编译阶段ÿ…...
![](https://i-blog.csdnimg.cn/direct/f023528a296d446f9bd2fe3b71e629b9.png#pic_center)
ZK-Rollups测评
1. 引言 Matter Labs团队和多个高校研究人员一起,发布2024年论文《Analyzing and Benchmarking ZK-Rollups》,开源代码见: https://github.com/StefanosChaliasos/zkrollup-benchmarking(Python) 其中: …...
![](https://www.ngui.cc/images/no-images.jpg)
redis生产使用场景(一):并行流+二级缓存
本文主要介绍 redis 缓存在线上的使用场景 由于业务的特殊性,在生产库用户表中,大概有 50 多万的测试用户,在真实业务计算中,要把测试用户给筛选掉,所以在计算前,需要把测试用户加载到 redis 缓存中&#x…...
![](https://www.ngui.cc/images/no-images.jpg)
EXCEL跨文件查询,指定条件列,返回满足条件的指定列
EXCEL跨文件查询,指定条件列,返回满足条件的指定列 Private Sub cmd_find_from_workbooks_Click() Dim S_Cols As String, thePath As String, Sor_Col As Integer, sz_Cols As Variant S_Cols T_jieguo_cols.Text sz_Cols Split(S_Cols, ",&quo…...
![](https://i-blog.csdnimg.cn/direct/3a9394486b814bfb8375b65a74a4d637.png)
[数据集][目标检测]流水线物件检测数据集VOC+YOLO格式9255张26类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):9255 标注数量(xml文件个数):9255 标注数量(txt文件个数):9255 标注…...
![](https://img-blog.csdnimg.cn/img_convert/50e73996fb40bb854b8febfb94d91dd4.jpeg)
StarRocks 存算分离 Compaction 原理
前言 StarRocks 中每次数据摄入都会生成一个新的数据版本,而查询时需要将所有版本数据进行合并才能获得一个正确的结果,如果历史数据版本太多,那么查询时需要读取的文件数也会很多,造成查询效率低下。因而 StarRocks 存在内部任务…...
![](https://i-blog.csdnimg.cn/direct/a95fb1abc9804e3bbc84fb29bd1c95ef.gif)
搭建ELK日志采集与分析系统
SpringCloud微服务实战——企业级开发框架 💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您…...
![](https://www.ngui.cc/images/no-images.jpg)
java集合中自动排序的treeset和treemap
底层 TreeSet 和 TreeMap 的底层架构都是基于红黑树实现的。红黑树是一种自平衡的二叉搜索树,其特性保证了插入、删除和查找操作的时间复杂度为 (O( log n \log n logn)),无论数据量多大,操作性能都能保持在合理的范围内。 1. 红黑树概述 红黑树是一种平衡二叉搜索树(…...
![](/images/no-images.jpg)
iis配置网站是什么/互联网营销具体做什么
一、下列命令可以用来操纵进程任务: ps列出系统中正在运行的进程。 kill发送信号给一个或多个进程(经常用来杀死一个进程)。 jobs列出当前shell环境中已启动的任务状态,若未指定jobsid,则显示所有活动的任务状态信息&a…...
![](https://img-blog.csdnimg.cn/img_convert/a003f6779ddc570d97fe84249495d87f.png)
网站建设计划书/360开户
linux mixerWindows 10’s Creators Update added a new live game-streaming feature. You can broadcast your gameplay in real time to your friends without any additional software. Windows 10的创作者更新添加了新的实时游戏流媒体功能。 您可以将您的游戏玩法实时广播…...
![](/images/no-images.jpg)
做第一个php网站/热狗seo顾问
周次 学习时间 新编写代码行数 博客量(篇) 学到知识点 本周 5 80(HTML的不知道算不算) 1 JAVA基础,网络基础的静态路由配置, XX XXX XXXX XXXX 转载于:https://www…...
![](https://img-blog.csdnimg.cn/c740f2db238344a7a8fa31d66e89f87e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pyo5rO96ZSQ,size_20,color_FFFFFF,t_70,g_se,x_16)
郑州网站建设公司哪家专业好/互联网营销师怎么报名
文章目录一、背景:二、解决:一、背景: win10 ,jdk18切换为jdk8,配置完JAVA_HOME,PATH,java -version测试仍显示jdk18 二、解决: 一番查证,找到问题所在: Oracle在使用过JDK后就会将JDK的配置…...
![](https://img-blog.csdnimg.cn/20190725093516717.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDEyOTQ5OA==,size_16,color_FFFFFF,t_70)
自己做的网站怎么上传网络/抖音推广
今天导入老师上周发的结束项目,发现需要下载最新版本的 tomcat , 然后百度了一下,发现有广告,所以我打算自己操作一下,发个图文教程。 因为之前学校使用的是 eclipse ,版本是8.5的。所以需要重新下载。 说实话&#…...
![](https://images2018.cnblogs.com/blog/974776/201805/974776-20180505003738174-1281180334.png)
怎么做网站作业/网络推广公司专业网络
数组是一段线性分配的内存, 它通过整数计算偏移并访问其中的元素. 数组是一种性能出色的数据结构. 1.数组字面量 数组字面量提供了一种非常方便地创建新数组的表示法. 多个用逗号分隔的值的表达式. 数组字面量允许出现在任何表达式可以出现的地方. 数组的第一个值将获得属性名0…...