网络基础二
文章目录
- 协议定制,序列化和反序列化
- 应用层
- 网络版计算器
- 协议的定制
- 序列反序列化
- 序列化
- 未复用版
- 反序列化
TCP是面向字节流的,你怎么保证,你读取上来的数据,是‘’一个“ “完整””的报文呢?

我们没有区分字符串里面有什么内容,连字符串都没有区分,我给你发了个你好,服务器这里read就一定能读到个你好 吗?
对方发过来因为网络问题只发过来一个你而已,但是之前并没有这个问题啊,那是因为网络好,数据量也不大。
就像之前管道写了好几次,但是读端把数据一下子全读上来了。
为什么觉得文件操作恶心,文件部分也和协议有关。
比如我把数据写到文件里,可能连续写了十几条消息,写好写,可是读的时候,里面有字符串有整数,当我读取时比较困难的把数据反向转换回来,且读的时候可能人家写了十几次我要读我调用一个fread把整个文件全都读进来了,此时你怎么保证你读上来的就是一个完整的拿到一段你想要的数据呢?
这个其实比较困难,因为这里有知识的残缺,必须解决。
那我按行读取不就完了吗,按行读取仅仅是对文件一种读取方式,那我一大堆二进制数据,你怎么保证读上来了关键字段呢?
正确对文件读写,对管道读写,对网络读写,尤其是面向字节流,你怎么保证你读上来的是一个完整的报文呢?
则今天服务器的read是有BUG的。
我们今天拷贝字符串从C到S,可是服务器就是从接受缓冲区里读,造成接受缓冲区快被打满了,此时客户端发数据可能只发了一部分这种情况
作为用户只需要在应用层通过write把数据拷贝到TCP发送缓冲区里,write调用直接返回,这个函数调用完了,可是这个数据不一定已经发给对方接受缓冲区!
数据不一定发送到网络里,所以write ,read,send , recv这样的接口不叫网络收发,实际上他的作用就是用户到内核拷贝,而真正决定网络收发的协议是由TCP协议决定的,因为只有TCP协议比较了解网络当前的健康状态和接收方的接受能力,所以必须由TCP全权负责:
1.什么时候发?
2.发多少?
3.出错了怎么办?
TCP协议是不是在OS内部实现的?
属于OS编译好的一部分。
所以OS属于内核,你所谓的用户把数据交给TCP这句话有点不太可信,实际上是用户把自己的数据交给了OS了,那你放心OS吗,当年讲文件操作时,其实是把用户的数据拷贝到文件的缓冲区里,最后由OS来把文件缓冲区的数据定期刷新到磁盘,如果你不相信OS,为什么当年你要相信呢?
所以用户把数据交给TCP,是用户把自己的数据交给了OS!
所以文件操作叫log.tx,今天的文件就叫做TCP。
此时把数据从用户层拷贝到内核你就别管了,作为用户直接返回就行了,OS会决定定期发多少。
发送谈完了再来谈谈接受,这时候就有点搞笑了,怎么搞笑呢?
作为接收方来讲,他要通过read调用,说白了是把接受缓冲区的数据拷贝到用户层缓冲区buffer[]
所以对方给我发了多少数据,什么时候发的,有没有把完整的数据一次全打包还是分三份打包过来?
接受缓冲区接受到的数据完全由OS决定了,对方发的时候可能把整个字符串分了三份发过来,也可能整体打包发过来,甚至把发了三四次写的数据最后打包整体发过来了。
假设读的时候一次全读完,有时候还读不完。
假设把缓冲区一次全读完,到底把数据有没有读到在应用层是一个我所认识的完整的报文,是一个字符串的一部分,还是读上来三四个报文,我们这里就完全不确定了,所以要对读上来数据进行更细节的分析。
所以在应用层我们要清楚,我们就必须得保证在应用层把协议定好,我们才能更好的进行读上来的数据的分析。
协议定制,序列化和反序列化
我规定好通信双方使用固定大小的报文,比如发送端是64字节,我在read返回值小于64字节,这个报文就不完整,我就把报文继续维持起来,当我下次继续读的时候一定要凑够64字节然后进行处理。
相当于把文件固定大小每次写一行,读也读一行,也叫订协议。
应用层
网络版计算器
方案一
发送“1+1”字符串,然后以类似方式返回
这样不太好,如果一下发了三四个请求,该如何区分呢?
方案二
定义请求结构体,直接把结构体大小字节的二进制数据发给对方,对方使用同样类型的结构体就可以提取出整数 a和整数 b,结果也是结构体处理
通信双发不发字符串,直接发对象,可以吗?
这是肯定可以的。但是在应用层不建议。
问题
- 同一个结构体先后在不同的编译器下编译出来的同一个结构体的大小一定是一样吗?
在内核层这样搞没问题,因为不管Windows还是Linux你们用的协议都叫TCP/IP协议。
可是用户应用层的编译器就千差万别了,编译出来的大小可能就是不一样的,因为有结构体对齐,他按8,他按4,大小就不一样。
比如说网络带宽特别差,接收方接受缓冲区已经被打满了,接收方给发送方说我来不及接收了先别发,所以TCP发送方就不发了,可是用户不知道,他就一直拷到TCP发送缓冲区里,四五个报文全在TCP缓冲区里,后来接收方说我好了你发吧, 我可以接受很大数据,TCP把四五个请求全给他发过去了,四五个请求是纯二进制的,那你怎么去区分一个一个报文呢?
我们该如何设计网络版本计算器的协议?
协议 = 结构体
整个结构体当中每一个结构体每一个字段都要让客户端和服务端约定好的。
约定好之后使用结构化的方式把约定表达出来,这就叫做定义出来了协议。
协议的定制
我们在微信聊天的时候约定通用结构体,这就叫定了聊天协议。
序列反序列化
我们在网络通信的时候,整个结构化的数据把多个字符串转化成一个字符串,这个过程称之为序列化。
把一个字符串打散成多个字符串转换成结构体化数据,叫做反序列化
我们最终为什么要序列反序列化呢?主要是序列反序列化之后方便网络进行收和发。
那发过去的一个大字符串,收过来一个字符串,我怎么保证把字符串收全呢?
后面还要设计报文和报文之间的分隔符。
所以方案一和方案二我们两个都用了。
不把多字符串整个成一个,那一个一个发,昵称啊,内容啊,时间啊,对端还要把多个字符串关联起来,难度太大。
我们要把创建套接字,绑定,监听,accept,connect全部封装成一个类Sock,不然写到Tcpserver类里面就很混乱。
这样Tcpserver调用起来逻辑很清晰。
客户端同理
让客户端和服务器双方使用同一套接口就行,不用来回写车轱辘代码了。
从此往后我们再也不写套接字了,因为我们有了小组件Socket.hpp的类Sock
前面说了要定制协议,就是设计Request和Response结构体,再把结构化的数据序列化成一个大字符串
我们的请求计算器可以从
int x int y char op
变为 字符串 “x op y”
接受缓冲区收到这种风格的字符串,也能解析,可是对方发来了多个这样的字符串,上层通过调用read();读取字符串的时候,他怎么保证上层读上来的是一个完整的报文呢?
有没有他读上来的是半个,一个半,两个。
如果你读上来的是两个,你怎么把这两个区分开?
如果你读上来的是一个半,你怎么证明一个半当中,哪一个是当前的,哪一个是下一个。
如果读上来是半个呢,你怎么知道报文多长呢?
请求和请求之间用特殊符号把他们分隔开
当上层读的时候碰到\n字符,\n之前的所有字符全部都收到了,就可做到报文和报文之间隔开了。
假设把缓冲区全部读上来,之后的问题就是字符串分析
把整个报文用\n分开,左边一个报文,右边一个报文。
不一定非得用\n,你可以用\3或者绝不会在报文中出现的分隔符
计算器场景比较简单,用\n分割一个个报文,这样我们再做字符串分析绝对可以分出一个一个子串,然后再对子串切割绝对能恢复成结构体
这样做有点简单,另一方面还是不够完善,因为有可能读上来的字符根本不是你想的那样,如果缓冲区只有半个报文呢,你怎么保证你读上来的是一个完整的报文呢?
有人说我只要判断有没有\n就可以了,没毛病,这样肯定可以的,不过今天我还想加一个东西,我想在报文前再加一个字段,长度
这个长度字段可以固定大小,也可以是字符串
这个长度是整个完整报文的长度是多少,这个长度不包括\n
我们还可以添加一个协议类型报头,让计算器支持浮点数或者整形计算。
今天就不这么复杂带这个协议类型了
最终的报文字符串风格就是这样子
将来读取的这一方,他可以一直读到\n,就可以把第一个字段读上来,也就是读到了第一个报文的长度。
也可以把全部缓冲区的报文都读上来,读上来之后根据第一个\n分析清楚是9,就知道第一个报文的长度,从第一个\n往后连续读取9个字符,我就能保证读到了一个完整的报文了。
100 + 200 \n这个\n一会再说。
后续字符串同理处理。
有人说200 后面的\n 要不要其实都无所谓了,因为已经有长度了,为什么还要带呢?今天把他带上未来想调试的话printf cout 直接打出来就会变成如下的样子。
很直观就能看到协议定制效果。
序列化
未复用版
请求“len\nx op y" y后面的\n其他地方加
反序列化
我们除了要解决一个报文内部的问题,这是序列化和反序列化
我们还要解决报文和报文之间的问题
课上代码因为在序列化过程中无论是客户端还是服务端都需要封装报头长度,外加最后的\n,所以不如在设置Encode来复用,他们两个都可以加报头和尾部\n
Encode
对"x op y" 添加报头长度\n 和 尾部\n
Decode函数
从len"\n"x op y"\n提取有效报文 “x op y”
内部
1.查找第一个\n,如果没找到直接返回,说明长度报头没有,就不玩了。
2.整个报文的长度应该是len(x op y的长度)+len长度报头本身的长度+2 (两个\n)
对要Decode的len"\n"x op y"\n…进行长度检查,如果整个读上来的报文长度不够说明这不是一个完整的报文请求,我也不玩了。
3.利用substr切出有效报文的子串
4.从package大长字符串移除此报文
一 把网络功能写出来
二 协议定好
三 把这俩货捏在一起 servercal.hpp Tcpserver
在tcpserver类中设置回调函数, 涉及了bind,bind的是calculato函数
相关文章:

网络基础二
文章目录 协议定制,序列化和反序列化应用层网络版计算器协议的定制序列反序列化序列化未复用版 反序列化 TCP是面向字节流的,你怎么保证,你读取上来的数据,是‘’一个“ “完整””的报文呢? 我们没有区分字符串里面有…...

从Full-Text Search全文检索到RAG检索增强
从Full-Text Search全文检索到RAG检索增强 时光飞逝,转眼间六年过去了,六年前铁蛋优化单表千万级数据查询性能的场景依然历历在目,铁蛋也从最开始做CRUD转行去了大数据平台开发,混迹包装开源的业务,机缘巧合下做了实时…...
springMVC 全局异常统一处理
全局异常处理⽅式⼀: 1、配置简单异常处理器 配置 SimpleMappingExceptionResolver 对象: <!-- 配置全局异常统⼀处理的 Bean (简单异常处理器) --> <bean class"org.springframework.web.servlet.handler.SimpleMappingExceptionReso…...
qt ubuntu i386 系统
sudo ln -s cmake-3.31.0-linux-x86_64/bin/* /usr/local/bin 【Ubuntu20.4安装QT6 - CSDN App】Ubuntu20.4安装QT6_ubuntu安装qt6-CSDN博客 sudo ../configure -release -platform linux-g-64 -static -nomake examples -nomake demos -no-qt3support -no-script -no-scriptt…...

BUUCTF—Reverse—helloword(6)
一道安卓逆向的签到题 下载附件 使用JADX-gui反编译工具打开(注意配环境),找到主函数 jadx 本身就是一个开源项目,源代码已经在 Github 上开源了 官方地址:GitHub - skylot/jadx: Dex to Java decompiler 发现flag …...

深入解析下oracle date底层存储方式
之前我们介绍了varchar2和char的数据库底层存储格式,今天我们介绍下date类型的数据存储格式,并通过测试程序快速获取一个日期。 一、环境搭建 1.1,创建表 我们还是创建一个测试表t_code,并插入数据: 1.2,…...

Elasticsearch 开放推理 API 增加了对 IBM watsonx.ai Slate 嵌入模型的支持
作者:来自 Elastic Saikat Sarkar 使用 Elasticsearch 向量数据库构建搜索 AI 体验时如何使用 IBM watsonx™ Slate 文本嵌入。 Elastic 很高兴地宣布,通过集成 IBM watsonx™ Slate 嵌入模型,我们的开放推理 API 功能得以扩展,这…...

如何搭建一个小程序:从零开始的详细指南
在当今数字化时代,小程序以其轻便、无需下载安装即可使用的特点,成为了连接用户与服务的重要桥梁。无论是零售、餐饮、教育还是娱乐行业,小程序都展现了巨大的潜力。如果你正考虑搭建一个小程序,本文将为你提供一个从零开始的详细…...

NFS搭建
NFS搭建 单节点安装配置服务器安装配置启动并使NFS服务开机自启客户端挂载查看是否能发现服务器的共享文件夹创建挂载目录临时挂载自动挂载 双节点安装配置服务器安装配置服务端配置NFS服务端配置Keepalived编辑nfs_check.sh监控脚本安装部署RsyncInofity 客户端 单节点安装配置…...

RNN与LSTM,通过Tensorflow在手写体识别上实战
简介:本文从RNN与LSTM的原理讲起,在手写体识别上进行代码实战。同时列举了优化思路与优化结果,都是基于Tensorflow1.14.0的环境下,希望能给您的神经网络学习带来一定的帮助。如果您觉得我讲的还行,希望可以得到您的点赞…...
Docker部署FastAPI实战
在现代 Web 开发领域,FastAPI 作为一款高性能的 Python 框架,正逐渐崭露头角,它凭借简洁的语法、快速的执行速度以及出色的类型提示功能,深受开发者的喜爱。而 Docker 容器化技术则为 FastAPI 应用的部署提供了便捷、高效且可移植…...

【Python数据分析五十个小案例】电影评分分析:使用Pandas分析电影评分数据,探索评分的分布、热门电影、用户偏好
博客主页:小馒头学python 本文专栏: Python数据分析五十个小案例 专栏简介:分享五十个Python数据分析小案例 在现代电影行业中,数据分析已经成为提升用户体验和电影推荐的关键工具。通过分析电影评分数据,我们可以揭示出用户的…...

Vue2学习记录
前言 这篇笔记,是根据B站尚硅谷的Vue2网课学习整理的,用来学习的 如果有错误,还请大佬指正 Vue核心 Vue简介 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。 它基于标准 HTML、CSS 和 JavaScr…...

TMS FNC UI Pack 5.4.0 for Delphi 12
TMS FNC UI Pack是适用于 Delphi 和 C Builder 的多功能 UI 控件的综合集合,提供跨 VCL、FMX、LCL 和 TMS WEB Core 等平台的强大功能。这个统一的组件集包括基本工具,如网格、规划器、树视图、功能区和丰富的编辑器,确保兼容性和简化的开发。…...

Redis主从架构
Redis(Remote Dictionary Server)是一个开源的、高性能的键值对存储系统,广泛应用于缓存、消息队列、实时分析等场景。为了提高系统的可用性、可靠性和读写性能,Redis提供了主从复制(Master-Slave Replication…...

logback动态获取nacos配置
文章目录 前言一、整体思路二、使用bootstrap.yml三、增加环境变量四、pom文件五、logback-spring.xml更改总结 前言 主要是logback动态获取nacos的配置信息,结尾完整代码 项目springcloudnacosplumelog,使用的时候、特别是部署的时候,需要改环境&#…...

KETTLE安装部署V2.0
一、前置准备工作 JDK:下载JDK (1.8),安装并配置 JAVA_HOME 环境变量,并将其下的 bin 目录追加到 PATH 环境变量中。如果你的环境中已存在,可以跳过这步。KETTLE(8.2)压缩包:LHR提供关闭防火墙…...

[RabbitMQ] 保证消息可靠性的三大机制------消息确认,持久化,发送方确认
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...
aws服务--机密数据存储AWS Secrets Manager(1)介绍和使用
一、介绍 1、简介 AWS Secrets Manager 是一个完全托管的服务,用于保护应用程序、服务和 IT 资源中的机密信息。它支持安全地存储、管理和访问应用程序所需的机密数据,比如数据库凭证、API 密钥、访问密钥等。通过 Secrets Manager,你可以轻松管理、轮换和访问这些机密信息…...

Java设计模式笔记(一)
Java设计模式笔记(一) (23种设计模式由于篇幅较大分为两篇展示) 一、设计模式介绍 1、设计模式的目的 让程序具有更好的: 代码重用性可读性可扩展性可靠性高内聚,低耦合 2、设计模式的七大原则 单一职…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...