网络版本的计算器

news2024/9/24 18:46:14

在这里插入图片描述

文章目录

  • 1. TCP协议通讯流程
  • 2. 应用层
    • 2.1 再谈 "协议"
  • 3. 网络版计算器
    • 3.1 服务器提供服务
      • 3.1.1 提取有效载荷
      • 3.1.2 服务器的反序列化
      • 3.1.3 计算服务
      • 3.1.4 服务器的序列化
      • 3.1.5 添加序列化后的长度
    • 3.2 客户端发送请求
      • 3.2.1 填充客户端请求
      • 3.2.2 客户端进行序列化
      • 3.2.3 客户端进行反序列化
  • 4. 引入json
    • 4.1 Request的json序列化
    • 4.2 Request的json反序列化
    • 4.3 Response的json的序列和反序列
    • 4.4 测试

1. TCP协议通讯流程

下图是基于TCP协议的客户端/服务器程序的一般流程:
在这里插入图片描述
服务器初始化
1.调用socket, 创建文件描述符。
2.调用bind, 将当前的文件描述符和ip/port绑定在一起; 如果这个端口已经被其他进程占用了, 就会bind失败。
3.调用listen, 声明当前这个文件描述符作为一个服务器的文件描述符, 为后面的accept做好准备。
4.调用accecpt, 并阻塞, 等待客户端连接过来。

客户端建立连接的过程
1.调用socket, 创建文件描述符。
2.调用connect, 向服务器发起连接请求。
3.connect会发出SYN段并阻塞等待服务器应答 (第一次)。
4.服务器收到客户端的SYN, 会应答一个SYN-ACK段表示"同意建立连接" (第二次)。
5.客户端收到SYN-ACK后会从connect()返回, 同时应答一个ACK段 (第三次)。

断开连接的过程
1.如果客户端没有更多的请求了, 就调用close()关闭连接, 客户端会向服务器发送FIN段(第一次)。
2.此时服务器收到FIN后, 会回应一个ACK, 同时read会返回0 (第二次)。
3.read返回之后, 服务器就知道客户端关闭了连接, 也调用close关闭连接, 这个时候服务器会向客户端发送一个FIN (第三次)。
4.客户端收到FIN, 再返回一个ACK给服务器(第四次)。

TCP在建立连接的时候,采用的是3次握手,在断开连接的时候,采用的是4次挥手
close关闭客户端的文件描述符,close关闭服务端的文件描述符。就是4次挥手中的2次

数据传输的过程
1.建立连接后,TCP协议提供全双工的通信服务, 所谓全双工的意思是:在同一条连接中,同一时刻,通信双方可以同时写数据,相对的概念叫做半双工:同一条连接在同一时刻,只能由一方来写数据。

2.服务器从accept()返回后立刻调用read(), 读socket就像读管道一样, 如果没有数据到达就阻塞等待。

3.这时客户端调用write()发送请求给服务器,服务器收到后从read()返回,对客户端的请求进行处理,在此期间客户端调用read()阻塞等待服务器的应答。

4.服务器调用write()将处理结果发回给客户端,再次调用read()阻塞等待下一条请求。

5.客户端收到后从read()返回,发送下一条请求,如此循环下去。

2. 应用层

2.1 再谈 “协议”

协议是一种 “约定”。socket api的接口,在读写数据时,都是按 “字符串” 的方式来发送接收的。如果我们要传输一些"结构化的数据" 怎么办呢?

struct messge
{
	string nick_name;//姓名
	string image;//图片
	string message;//消息
}

如果我们想发送的是这样的消息。TCP是字节流传输,那么可以就会遇到结构体对齐的问题,这样得到的数据就不对。

我们就需要用序列化和反序列化
比如,假设我们以冒号作为分割符,将上面的结构体转换成"字符串",nick_name:image:message。这种方法就叫做序列化,然后把这样的"字符串"传到对端,在此之前,我们应该有我们的协议制定:有几个字段,每个字段有什么含义。传到对端之后,按照这样的协议约定,把这样的"字符串"再转换成结构体。这叫做反序列化。

还有一个问题:字符串的整体长度对方是如何知道的呢
我们需要定制协议:可以设置一个4字节大小的空间,在序列化之后,把这个空间放到序列化之后的字符串的开始之前。这个也叫做自描述长度协议

3. 网络版计算器

我们需要实现一个服务器版的计算器,需要客户端把要计算的两个数发过去,然后由服务器进行计算, 最后再把结果返回给客户端。

约定方案一:
客户端发送一个形如"1+1"的字符串。
这个字符串中有两个操作数,都是整形。
两个数字之间会有一个字符是运算符。
数字和运算符之间没有空格。

约定方案二:
定义结构体来表示我们需要交互的信息。
发送数据时将这个结构体按照一个规则转换成字符串,接收到数据的时候再按照相同的规则把字符串转化回结构体。

下面我们将实现一下大致方案二的代码:
在这里插入图片描述
我们让服务器去提供这样的一个计算服务。
在这里插入图片描述
在这个Protocol.hpp去定制我们的协议。
在这里插入图片描述
我们定制了请求与响应的类来完成我们的操作。那么根据我们刚刚所说的,这两个类都需要序列化和反序列化。
在这里插入图片描述
还有我们需要知道发送的字符串的长度以及如何提取报文里的有效载荷。
在这里插入图片描述

3.1 服务器提供服务

在这里插入图片描述
这里为什么有一个buff和一个inbuff呢
原因是:这里的一次读取是128字节,那么如果我们发送的字符串长度是大于128字节的,那么就说明一次读取不完,我们就需要把每次读取的数据放到inbuffer里,再做判断。
在这里插入图片描述
读取成功之后,我们需要检查inbuffer里是否至少有一个完整的报文。

3.1.1 提取有效载荷

那么我们如何去检查呢
在这里插入图片描述
这个函数的作用是:检测len和有效载荷必须符合要求,才返回有效载荷和len,不然就是一个检测函数,把len设置成0。

我们以7\r\n100+200\r\n来为例:
在这里插入图片描述
这里我们要先判断传进来的字符串中有没有分隔符,如果没有就直接返回空字符串。这里我们把分隔符定义成\r\n:
在这里插入图片描述
如果存在这样的分隔符,我们就把分隔符前面的数字提取出来:
在这里插入图片描述
提取长度之后,我们要判断这个长度和有效载荷:
在这里插入图片描述
如果剩余的长度大于等于intlen说明至少有一个完整的报文,如果小于说明读取的有效载荷不全,就返回空字符串。
在这里插入图片描述
有完整的报文,我们就把它提取出来。

但是到这里还没有结束:
在这里插入图片描述
我们需要把传进来的字符串中除去刚刚提取出来的报文,不然下一次提取还是这个报文。

这样我们就可以把完整的有效载荷返回。

3.1.2 服务器的反序列化

在这里插入图片描述
如果已经获取了一个完整的报文,我们就把它进行反序列化,填充到req对象中。
在这里插入图片描述

3.1.3 计算服务

在这里插入图片描述
反序列化完成之后,我们就需要把它进行计算,把结果填充到Response。
在这里插入图片描述
这里因为只有我们自己使用,加上了static。

3.1.4 服务器的序列化

在这里插入图片描述
得到计算结果后,我们需要把这个结果序列化成一个字符串。
在这里插入图片描述
我们制定协议:在退出码和结果直接添加一个空格。

3.1.5 添加序列化后的长度

在这里插入图片描述
我们把计算结果序列化之后,我们需要在前面添加字符串的长度,

    // "exitCode_ result_"
    // "len\r\n""exitCode_ result_\r\n"

我们以/r/n来制定协议。
在这里插入图片描述

3.2 客户端发送请求

在这里插入图片描述
如果用户输入quit,就continue直接进行循环判断,不往下写入。

3.2.1 填充客户端请求

在这里插入图片描述
下面我们就需要把输入到message里面的表达式填充到req里。
在这里插入图片描述
在这里插入图片描述

先把message格式化输入到strtmp里。然后只要有OPS里任意一个字符就切割出左操作数和右操作数。
在这里插入图片描述
然后我们把操作数和操作符都填充进去。但是这里不能处理负数。

3.2.2 客户端进行序列化

在这里插入图片描述
填充到req里面之后,我们需要进行序列化,然后给前面添加长度。

在这里插入图片描述
在这里插入图片描述
添加长度的方法和服务器添加长度是一样的。

3.2.3 客户端进行反序列化

在这里插入图片描述
当发送的消息添加协议之后,发送给服务器,发送成功后进行读取到buff里,然后将读取的数据进行提取数据,这里和服务器端也是一样的。

读取的结果进行反序列化到resp里。然后把退出码和结果打印出来。
在这里插入图片描述

我们简单测试一下:
在这里插入图片描述

4. 引入json

我们这里自己去写序列化和反序列化十分麻烦,我们可以使用第三方库来完成这方面工作:

yum install -y jsoncpp-devel

安装成功后,可以看到头文件:
在这里插入图片描述
那么我们该如何使用呢?
在这里插入图片描述
我们可以采用条件编译的形式,如果我们自己定义了宏就使用我们自己的,否则就使用json。

4.1 Request的json序列化

首先,引入头文件:

#include <jsoncpp/json/json.h>

第一步,我们要创建json里面的Value对象,它是一个万能对象,能接受任何类型:

Json::Value root;

json是基于KV的,序列化的时候,会将所有的数据内容,转换成为字符串。
在这里插入图片描述
然后,我们需要定义一个FastWriter(或者使用StyledWriter)对象,把root这个对象转换成字符串形式:
在这里插入图片描述
这样就完成了序列化工作。

4.2 Request的json反序列化

反序列化我们需要json里面的Reader对象:
在这里插入图片描述
然后将in里面的字符串反序列化到root里,然后再通过root填充到Request里的成员变量里。
在这里插入图片描述

4.3 Response的json的序列和反序列

在这里插入图片描述
在这里插入图片描述

4.4 测试

那么在编译的时候,因为是第三方库,我们需要在makefile里去指定库:
在这里插入图片描述
并且在条件编译的时候,我们可以命令行去定义:
在这里插入图片描述
这样就会去使用我们自己定义的协议。
在这里插入图片描述
这样说明这里为空,就会使用json。

json版结果如下:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

为什么我挖不倒sql注入啊!

为什么我挖不倒sql注入啊&#xff01; 背景一句话讲原理小白速挖注入 背景 不知道是不是初学安全的小伙伴都和我一样&#xff0c;刚开始学的时候&#xff0c;诶挺简单啊&#xff01;我咋这么聪明一学就会&#xff0c;靶场轻轻松松过关&#xff0c;到了实战根本挖不出来&#x…

【C++】float / double 与 0 值比较

【C】float / double 与 0 值比较 文章目录 【C】float / double 与 0 值比较1. 概述不同1.1 - float 与 double 实际存储1.2 - C 语言与 C 中不同 2. 比较方法2.1 - C 风格比较2.2 - 使用 limits 函数 3. 参考链接 References 1. 概述不同 当然使用普通的比较没有问题&#xf…

项目管理中,WBS与项目计划有什么区别?

为了成功完成项目并控制成本&#xff0c;我们有必要采取科学的项目管理方法。实现这一目标的工具是项目计划和工作分解结构&#xff08;WBS&#xff09;。 WBS 与项目计划是项目管理中必不可少的工具&#xff0c;但两者有不同的用途。WBS精确描述了项目工作和可交付成果&#…

前端vue入门(纯代码)26_多级路由

如果耐不住寂寞&#xff0c;你就看不到繁华。 【24.Vue Router--多级路由】 [可以去官网看看Vue Router文档](嵌套路由 | Vue Router (vuejs.org)) 在实际开发中&#xff0c;我们不单单会使用到一层路由&#xff0c;有时候会涉及到两层或两层以上的路由&#xff0c;多级路由…

带清除按钮的输入框

// index.html <!DOCTYPE html> <html> <head><meta charset"utf-8"><meta name"viewport" content"widthdevice-width, initial-scale1, maximum-scale1"><title>测试 - layui</title><link rel&…

Gof23设计模式之桥接模式

1.概述 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;它将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。它的核心思想就是将一个大类或一系列紧密关联的类拆分成两个独立的抽象和实现部分&#xff0c;以便能够更加灵活地扩展…

html相关面试题

html相关面试题 1.html和css中的图片加载与渲染规则是什么样的&#xff1f;2.title与h1的区别、b与strong的区别、i与em的区别&#xff1f;title 和 h1 的区别b 和 strong 的区别i 和 em 的区别最后 3.script 标签为什么建议放在 body 标签的底部&#xff08;defer、async&…

Duplicate keys detected: ‘0‘. This may cause an update error.

问题 vue报错 Duplicate keys detected: ‘0‘. This may cause an update error. 原因 <div v-for“(item,id) in items” :key"id”>{{item.name}} </div><div v-for“(item,id) in items” :key"id”>{{item.address}} </div>:key重…

G1垃圾收集器

一、内存结构 G1将堆内存划分成2048个相同大小的内存Region&#xff0c;一般Region大小等于堆内存大小除以2048&#xff0c;比如堆内存有4个G&#xff0c;每个Region大小为2M&#xff08;-XX:G1HeapRegionSize参数可以设置Region大小&#xff0c;一般不推荐修改&#xff09; G…

C. Strong Password

Problem - C - Codeforces 思路&#xff1a;根据题意我们能够知道就是对于每一位都要再区间范围内&#xff0c;并且不是s的子序列&#xff0c;我们先看第一位&#xff0c;第一位有l[1]-r[1]这几种选择&#xff0c;假如说某一种选择在s中没有那么我们就选择以这个开头的作为答案…

一文讲透进销存管理,和4款值得推荐的进销存管理软件!

进销存管理已经成为当下很多企业和商户必须面对的问题&#xff0c;想要在激烈的市场竞争中取胜&#xff0c;告别混乱管理&#xff0c;必须要有完善合理的进销存管理方法。 那么&#xff0c;进销存管理具体指的是什么&#xff0c;如何做好进销存管理&#xff0c;以及市面上有哪些…

L1-033 出生年(c语言)

作者 陈越 单位 浙江大学 以上是新浪微博中一奇葩贴&#xff1a;“我出生于1988年&#xff0c;直到25岁才遇到4个数字都不相同的年份。”也就是说&#xff0c;直到2013年才达到“4个数字都不相同”的要求。本题请你根据要求&#xff0c;自动填充“我出生于y年&#xff0c;直到…

【风险管理】认知风险管理

NLP技术的商业应用 介绍 机器学习 (ML) 应用程序已经无处不在。每天都有关于自动驾驶汽车人工智能、在线客户支持、虚拟个人助理等的新闻。然而&#xff0c;如何将现有的商业实践与所有这些惊人的创新联系起来可能并不明显。一个经常被忽视的领域是应用自然语言处理 (NLP) 和深…

极智AI | cv::cuda::GpuMat数据排布的误区

欢迎关注我的公众号 [极智视界]&#xff0c;获取我的更多经验分享 大家好&#xff0c;我是极智视界&#xff0c;本文来谈谈 cv::cuda::GpuMat 数据排布的误区。 邀您加入我的知识星球「极智视界」&#xff0c;星球内有超多好玩的项目实战源码下载&#xff0c;链接&#xff1a;…

Tomcat NIO 实现

1. tomcat网络整体架构 来自 https://www.cnblogs.com/cuzzz/p/17499364.html 上图是tomcat整个网络请求模型 Acceptor线程作为监听线程,会通过通过 accept 方法 获取连接&#xff0c;该线程没有使用selector进行多路复用&#xff0c;使用了阻塞式的accept有请求连接后&#x…

UE5《Electric Dreams》项目PCG技术解析 之 PCGCustomNodes详解(二)Look At

继续解析《Electric Dreams》项目中的自定义节点和子图 文章目录 前导文章Look AtExecute with ContextPoint Loop Body使用范例Get Actor Data节点的设置LookAt节点的设置Add节点的设置 小结 前导文章 《虚幻引擎程序化资源生成框架PCG 之 UPCGBlueprintElement源码笔记&…

阿里云轻量应用服务器使用教程(从0到1网站上线)

阿里云轻量应用服务器怎么使用&#xff1f;阿里云百科分享轻量应用服务器从选配、配置建站环境、轻量服务器应用服务器远程连接、开端口到网站上线全流程&#xff1a; 阿里云轻量应用服务器使用教程 轻量应用服务器很火爆因为成本足够低&#xff0c;阿里云2核2G3M带宽轻量服务…

第一批用ChatGPT坐牢的人,都玩的是哪些套路?

通过GPT在短时间内生成完整诈骗话术&#xff0c;套路啊套路 “虚拟角色”可以虚拟客服&#xff0c;还可以虚拟恋人玩杀猪盘 让受害人以为自己“坠入爱河” 套路还是从前的套路 但骗子用上了新的工具 又换上了很多马甲 防不胜防 你以为OpenAI不知道骗子会用这个工具来做坏…

数据库之MySQL数据操作练习

目录 练习内容 worker表要求 创建的表的表结构 表中的数据内容 对数据的操作 1.显示所有职工的基本信息 2.查询所有职工所属部门的部门号&#xff0c;不显示重复的部门号 3.求出所有职工的人数 4.列出最高工和最低工资 5.列出职工的平均工资和总工资 6.创建一个只有职…

深度学习之权重初始化

在深度学习中&#xff0c;神经网络的权重初始化方法( w e i g h t weight weight i n i t i a l i z a t i o n initialization initialization)对模型的收敛速度和性能有着至关重要的影响。说白了&#xff0c;神经网络其实就是对权重参数 w w w的不停迭代更新&#xff0c;以达…