企业网站设计合同,湖北强涛建设工程有限公司网站,门窗 东莞网站建设,建网站麻烦拍照备案审核多久引言#xff1a;
北京时间#xff1a;2023/9/14/19:13#xff0c;下午刚刚更完文章#xff0c;是一篇很久很久以前的文章#xff0c;由于各种原因#xff0c;留到了今天更新#xff0c;非常惭愧呀#xff01;目前在上学校开的一门网络课程#xff0c;学校的课听不了一…引言
北京时间2023/9/14/19:13下午刚刚更完文章是一篇很久很久以前的文章由于各种原因留到了今天更新非常惭愧呀目前在上学校开的一门网络课程学校的课听不了一点还没有我自己看书来的快并且因为我们对网络基础知识已经有了一定能的理解当然这部分理解是我们对网络概念框架的理解比较宽泛没有书本上那么丰富细节但是已经足够我们使用因为我们对其的理解是从整体框架出发本质还是那句话学校的课听不了一点咱直接开摆。然后这几天经历的事情还是比较丰富的在之后的引言中我们慢慢回顾最重要的还是在前几天学校开学啦目前给我的感觉就是困意十足中午睡觉睡的是真舒服根本醒不来哈哈哈有待加强身体锻炼剩余就是积极更文并且在今天我找到了一个白嫖书的好方法那就是帮图书馆推销有关计算机方面的书籍只要到达1000浏览量我们就能白嫖一本自己想要的书啦感情真不错哈哈哈积极更文我能行该篇博客就让我们来学习一下有关应用层方面的知识序列化与反序列化。 学习应用层相关知识
在上篇博客中我们对服务端中的日志概念和守护进程概念进行了理解并且自己实现了相应代码最后让服务端执行相应代码让服务端成为了一个含有日志的守护进程从而实现服务端持续运行和记录日志的功能。搞定了这些知识之后无论是服务端的多执行流运行还是服务端的网络通信或者数据处理亦或者是客户端的网络通信数据传输我们都有了一定的理解所以有关网络套接字相关的知识当然也就是上述服务端、客户端、网络通信的知识我们就讲到这里并且因为我们一直使用的都是TCP/UDP协议也就是一直处于网络模型中的传输层此时对于传输层相关的知识我们也就学习到这该篇博客以及之后的博客我们重点讲解的都是应用层相关知识当然重点也就是应用层相关协议如HTTP/HTTPS当然不止如此在讲解应用层协议相关知识时我们还会穿插讲解有关序列化和反序列化相关的知识具体有待下述深入学习。
回顾之前知识强调相关注意点
在之前传输层学习有关套接字网络通信时我们对IP地址以及端口号都有了很强的认识然后慢慢的我们了解了网络字节序和点分十进制相关知识最终一点一点铺垫对无论是套接字整体框架还是套接字细节知识我们都有了自己的理解相比于套接字整体框架接口UDP/TCPsocket、bind、recvfrom、sendto/socket、bind、listen、acceptconnect、readrecv、writesend此时我们对细节知识也就是网络字节序和点分十进制相关知识也有了一定的了解其中对于网络字节序也就是主机序列和网络序列的转换我们知道可以使用的接口有htons、ntohs、htonl、ntohl、inet_addr、inet_ntoa、inet_aton当然我们知道前者一般是提供给端口号16位/32位使用后者一般是提供给IP地址使用因为IP地址除了需要将主机序列转化为网络序列之外它还需要将点分十进制的数据“124.71.57.104”转换为二进制数据当然其中inet_addr和inet_aton是一样的都是将IP地址从点分十进制转换为二进制序列反之inet_ntoa同理。
回顾了上述有关使用套接字进行网络通信的基础知识当然不包括有关多执行流进行数据处理相关知识此时我们对套接字就又有了一定的认识脑子是一个健忘的东西所以此时我们对地址转换函数也就是inet_ntoa和inet_aton要进行一个注意点强调本质也就是因为inet_ntoa接口在我们获取点分十进制的IP地址时它的返回值是一个指向静态数组的字符指针那么此时问题就来了其一为什么返回的一定是一个静态数组其二为什么不能返回一个静态数组首先第一个问题在C语言中不存在字符串类型当然C中的字符串类型本质只是一种利用堆空间对字符进行的封装处理而已所以如果想要存储字符串在C语言中就只有三个方法栈/堆/静态一个是使用字符数组缓冲区另一个是使用堆空间还有一个就是使用静态存储明白了这点之后我们就知道如果我们想要获取到点分十进制的IP地址那么在inet_ntoa接口中它就需要将转换完成的IP地址存放到堆区或者是静态区上否则就会导致数据点分十进制IP地址随着函数栈帧的销毁而销毁而又因为如果是将数据存放到堆区上会增加用户对该接口inet_ntoa的使用成本需要用户自己进行堆区的释放防止内存泄露问题所以最终该接口是将数据存放到了静态区上static也就是它的返回值是一个静态数组的指针此时因为该接口的返回值是一个静态存储数据那么该接口此时就有可能存在线程安全问题虽然在服务端场景下该接口不会被多线程访问但是在其它场景下就有可能会因为多线程同时访问该接口造成线程安全问题最后导致程序异常所以类似于这种我们需要将某种数据转换为某种数据的过程一般都会存在线程安全问题本质在于该接口内部是否进行线程安全处理互斥锁/同步机制/信号量当然此时inet_ntoa接口中可能就没有进行线程安全处理所以当以后我们碰到这一类场景时就可以使用inet_ntop接口具体参看使用说明反之因为inet_aton使用的是我们自己提供的字符数组buffer直接将返回值写入到对应的缓冲区中所以不存在静态存储问题不存在线程安全问题。
了解TCP协议下客户端和服务端的一般连接流程
对于这块知识目前我们只是简单理解只是为了引出“三次握手和四次挥手”的概念然后对其有一定的认识而已当然此时我们是在对TCP版本下的服务端/客户端进行了解而不是UDP版本服务端/客户端本质原因也就是TCP需要先建立连接而UDP不要并且我们在进行套接字网络通信代码编写时使用的都是操作系统提供给我们的系统调用接口并没有很好的从底层去理解网络通信的过程所以此时为了深入了解有关知识我们就可以参考下图通过图示我们来深入了解一下服务端和客户端之间建立连接的过程。
客户端和服务端的三次握手过程 ok此时有了图示对于三次握手的理解我们就有了很强的抓手对于引出一些概念也较为轻松从上图我们可以看出当初我们在进行套接字网络通信编码的过程是一个应用层场景而客户端和服务端的三次握手是一个传输层场景所以此时根据我们对TCP/IP网络协议栈的理解我们明白只有当我们在上层应用层完成了套接字的创建向系统申请了对应资源并且调用了connect接口此时客户端操作系统才会帮我们进行后序的一系列操作当然具体过程也就是上图中所示首先操作系统会将SYN标志位和seq客户端初始序列号封装到TCP数据报中进入SYN_SENT状态然后该数据报经过网络协议栈发送到远端服务器上当远端服务器监听到该连接请求服务器就会停止accept阻塞状态然后同理将SYN标志位和自己的seq服务端初始序列号封装到TCP数据报中只不过此时服务端还会将ACK确认标志位也封装到TCP数据报中进入SYN_RCVD状态然后同理将该数据报发送回客户端最终客户端接收到之后也将ACK确认标志位和自己的初始序列号、服务端的初始序列号发送回去服务端应用层accept返回服务端与客户端连接成功两者都进入ESTABLISHED 状态。
客户端和服务端的四次挥手过程
当客户端和服务端都处于ESTABLISHED 状态也就是完成客户端和服务端之间的连接时此时客户端和服务端就可以进行数据传输并且此时服务端和客户端就可以利用对应客户端和服务端的序列号seq和确认号ack来保证数据传输的可靠性啦当客户端和服务端完成数据传输之后它们就会进行四次挥手过程具体如下图所示 同理如图所示此时服务端和客户端任何一方在应用层调用close接口之后都可以向对方发送一个封装了FIN标志位的数据报假如此时是客户端先向服务端发送FIN标志位那么此时客户端就会进入FIN-WAIT-1状态停止发送数据但依然可以收到服务端数据然后当对方接收到对应数据报之后进入CLOSE-WAIT状态然后同理向对方发送一个封装了ACK确认标志位的数据报客户端进入FIN-WAIT-2状态最后服务器再次发送封装了FIN标志位的报文表示服务端向客户端发送断开连接请求服务端进入LAST-ACK最后确认态客户端接收到之后进入TIME-WAIT时间等待状态之所以不是关闭状态本质是因为客户端的TCP连接还没有释放只有经过2*MSL最长报文段寿命的时间后客户端才会被真正关闭最终客户端和服务端之间的连接彻底关闭。
总结上述就是有关服务端和客户端之间的一般连接流程其中涉及到的大多是应用层和传输层之间的知识感兴趣的同学可以参考该篇博客深入理解相关知识TCP协议流程详解 正式进入该篇博客的主题有关序列化和反序列化相关的知识
明白了上述有关TCP协议下服务端和客户端的一般连接流程当然也就是服务端和客户端的三次握手以及四次挥手的知识此时我们对数据传输过程的建立就有了一个更加全面的认识当然在之后讲解有关TCP/IP等协议时我们还会深入了解不过在该篇博客中此时我们重点来看看有关序列化和反序列化的知识。
什么是序列化和反序列化呢
简简单单学习一个新知识同理三步走是什么/为什么/如何实现所以对于应用层中有关序列化和反序列化相关的知识我们就从这三个角度来学习同理每次对于新知识我都是从是什么/为什么出发最后再将其用代码实现而对于博主我的这个学习过程本质就是一个模板化过程一个我自己规定好了的过程所以同理对于序列化和反序列化来说它们也就是在对某个或者某种过程进行模板协议的定制。当明白了这点之后假如此时该过程是一个网络数据传输过程那么我们就可以以最常见的服务器和客户端为例来看看服务端和客户端在进行网络数据传输时如何对数据进行序列化和反序列化了。王炸直接丢出来该假设也就是该篇博客的重点也就是后序代码实现的关键。所以此时我们明白序列化和反序列化过程是一个对网络传输数据的处理过程并且从服务端和客户端角度来看序列化和反序列化就是一个对客户端请求数据和服务端响应数据的处理过程如我们想要将客户端请求数据发送给服务端那么此时无论你发送的是何种结构何种类型的数据最后服务端接收到的一定是一串字节流数据无TCP/UDP区分当然也就是二进制数据反之同理客户端接收到的数据也一定是字节流数据所以此时这个将数据转化为字节流的过程我们就称为序列化过程反之当服务端或者客户端接收到对应字节流将其转化为对应数据解码的这个过程我们就称为反序列化过程。当然此时有的同学就会想那我自己在实现客户端或者服务端的时候是不是就要把对应的数据搞成一个二进制数据然后把二进制数据通过系统调用接口发送出去或者是接收到某个二进制数据我就要把这个二进制数据搞成对应十进制数据或者是对应十进制数据的编码数据有这个想法没有任何问题因为这个过程是的的确确存在的只不过这个过程计算机操作系统默认就会帮我们完成而已谈上述字节流式的序列化和反序列化过程只是帮助我们更好的理解什么是序列化和反序列化罢了从底层出发明白序列化和反序列化的重要性和最基本使用场景。有了上述知识的铺垫我也就不唯唯诺诺了本质还是同理序列化和反序列化就是在对某过程进行规定协议上述双方将数据转化为字节流的过程本质也就是序列化和反序列化的精髓字节流就是规定就是协议就是标准。所以基于应用层而言序列化和反序列化就是在将某种类型、某种格式的数据转化为一种统一的格式将某种统一的格式转化为某种类型、某种格式。最后明白基于目前而言应用层一般的序列化和反序列化格式已经有标准协议供给我们使用当然也就是大部分的服务端和客户端使用的都是对应协议其中有Json/Xml/Protocol Buffers/MessagePack所以当服务端和客户端使用了这些协议无论是服务端还是客户端它们的数据首先就会被序列化或者反序列化为对应协议规定的格式如下就是Json中两种不同的协议格式 从图中可以看出对于Json而言它在对数据进行格式控制时使用的是哈希[Key/Value]的方式并且外部都使用大括号括起来这样实现的好处就在于进行数据提取时非常方便具体后续详谈。
为什么要进行序列化和反序列化呢
对序列化和反序列化是什么的概念有了一定的理解之后我们的三步走就成功走出了第一步好比冬天来了春天还有远吗当然前两步都是基于概念理解在没有真正见过代码之前 序列化和反序列化依旧是在扯淡只不过是扯的详细了点而已哈哈哈并且对于上述直接理解、灌输序列化和反序列化的概念目前给我的感觉除了比较抽象之外还有就是为什么要进行序列化和反序列化呢在没有解决这个问题之前序列化和反序列化给我的感觉就像是无根之萍非常的漂浮所以此时为了让我们对其概念有更加全面的认识我们就需要一个强有力的抓手搞清楚为什么服务端和客户端在进行网路数据传输时一定要有序列化和反序列化过程。
在搞清上述问题之前我们需要明白一个点客户端在向服务端发送消息时发送的不单单只有消息内容伴随着对应的消息内容还存在非常多的其它数据如发送时间、用户信息等… 所以当我们在发送数据时发送的不仅仅只是一个字符串数据而应该是一个结构化数据。本质同理使用结构化数据的原因就在于结构化数据不仅支持嵌套更加复杂的数据结构在结构化数据需要修改时还可以直接添加或者删除某个字段维护使发送数据这个过程的灵活性和扩展性大大提高。明白了上述知识此时对于数据传输过程为什么进行序列化和反序列化我们就有了切入点本质因为传输的是结构化数据所以此时就会导致在不同的应用程序中结构体字段大不相同而因为结构体字段不同此时就有可能会导致不同的数据格式表示相同数据的问题最终导致被传输数据无法被接收方正确解析和处理数据传输失败。 所以因为该问题此时我们就需要对传输数据进行序列化和反序列化这也就是我我们进行序列化和反序列化的重要原因之一因为序列化和反序列化带来的好处并不止于此如将数据序列化和反序列化之后该数据就可以进行跨语言和跨平台传输本质同理因为我们可以自己定制协议格式或者是使用已经存在的标准协议将数据转化为一个可以被所有平台和语言解析使用的通用格式。当然序列化和反序列化还可以增强数据的封装性和安全性等…本质也就是我们在定制序列化和反序列化协议的时候不止可以定制一种格式控制协议还可以定制一种数据安全协议如对数据进行加密处理对数据添加报头对数据进行分隔符控制等…。
深入理解序列化和反序列化
行文来到此处我们对序列化和反序列化的知识就有了一定的了解并且也有了抓手明白对数据进行序列化和反序列化的本质目的就是让接收方接收到数据的同时可以正确的解析识别数据而已。同理上述概念中有关字节流的说法将数据序列化成字节流再发送到远端本质的目的也就是让远端可以接收并识别该数据而已因为远端也一定是某种计算机协议规定该计算机只能接收字节流。所以同理当该字节流被解析为特定数据之后上层某应用程序想要读取该数据那么该应用程序首先需要对该数据进行反序列化操作而该应用程序想要进行反序列化操作它同理需要有一个抓手依赖当然聪明的我们很快能反应这个抓手一定和发送数据时进行的序列化过程是相同的最终该应用程序凭借这个依赖成功的将对应数据读取。再本质一些理解也就是应用程序在反序列化数据时一定要知道什么东西代表的是什么东西 如我们将数据序列化成一个string或者是vector数组亦或者是Hash映射在反序列化时我们就需要知道对应string前后字符代表的是什么vector对应下标代表的是什么Hash对应Key值代表的是什么然后根据这个已知将数据读取出来所以这个已知就是我们序列化和反序列化的抓手而这个定义已知根据已知进行序列化和反序列化的过程我们就称为定制协议的过程。
总而言之 序列化和反序列化并不是什么问题无论是我们自己定制协议还是使用标准化协议结合上述知识从代码角度去看只不过就是定义一个头文件在头文件中实现一个类C类内除了必要的成员变量之外还含有两个成员函数一个俗称序列化函数一个俗称反序列化接口而在序列化接口中我们将类内成员变量进行特定格式的控制天生知道在反序列化接口中依据序列化格式将数据重新提取到对应成员变量中当然具体在这两个过程中是否存在加密等操作我们不关心。最后在客户端中包含该头文件调用其中的序列化接口在服务端中同理包含该头文件调用其中的反序列化接口。形成了一个让客户端和服务端看见同一份资源类然后客户端和服务端直接通过该资源传输数据的假象好比客户端初始化类内成员变量服务端就可以直接读取类内成员变量的一个过程。 所以这也就是序列化和反序列化的顶级好处完美的确保了数据的一致性和可靠性。
从代码分析序列化和反序列化
在上述三步走中的两步走我们已经走完了同理无论你理论多么详细在没看见代码之前一切都是浮云所以接下来就让我们进入该篇博客的最后一个知识点也是有关序列化和反序列化的最后步骤自己使用代码实现序列化和反序列化过程当然同理上述所说该过程目前已经有非常多标准供给我们直接使用头文件但我们为了更加全面的认清该过程此时我们就打算自己实现一次当然肯定只是简单实现。只不过在进行序列化和反序列化之前我们需要一个场景所以此时我们就以一个网络版本计算器为场景来看看具体如何实现数据的序列化和反序列化吧
网络版本计算器代码实现
简简单单在实现网络版本计算器之前我们需要先理清思路明白大致的实现过程以及基本步骤此时第一步同理上述深入理解当中所说我们需要定义一个头文件agreement.h然后在该头文件中定义对应的结构化数据类同理因为该结构化数据需要被序列化和反序列化处理所以此时在该类中除了结构化数据成员变量之外还需要伴随两个接口一个负责将成员变量序列化便于传输一个负责将成员变量反序列化便于接收当然具体如何序列化/反序列化序列化成何种格式这都有待于在深入学习过程中从代码发现这里不重点强调此时我们需要明白的是在网络版本计算器中当客户端向服务端发送数据之后服务端需要根据客户端请求完成某些任务然后将对应数据的处理结果响应回给客户端所以在agreement.h头文件中我们就需要有两套协议一个表示请求协议一个表示响应协议一个负责传输需处理数据一个负责传输结果数据。明白了这些之后此时我们就可以进入代码实现啦
注意 因为此时该部分代码涉及非常多细节方面的知识如果我们想要在理解序列化和反序列化的过程中将这些细节知识解决我们就需要一部分一部分的来看相关代码不然会导致代码非常多许多细节无法深入透彻所以此时我们首先将其分为三大块第一块知识为服务端客户端使用套接字通信过程当然这块在之前我们已经深入理解过所以此次我们基于回顾并且带有一定创新的角度看代码第二块知识为分析服务端客户端中包含头文件以及调用接口当然该部分就是为了之后的序列化和反序列化协议定制做准备第三块知识为规定结构化数据和序列化反序列化接口当然这块知识身为该篇博客重点中的重点它其中涉及的知识较为复杂有待深入理解。此时有了这三大块知识的前后联系对于整块代码我们就有了一定的抓手清楚接下来我们如何一步一步的执行代码不会因为任意调用接口导致混乱下面就让我们来分别看看这三块知识吧
第一块服务端和客户端使用套接字进行网络通信代码 当然这块代码在之前学习网络套接字相关知识时我们已经重点强调且频繁理解过了而正是因为我们频繁理解过这块知识所以此时我们对其有了一定新的认识那就是将其进行封装好处不言而喻这样我们就不需要每次都对套接字相关接口进行初始化过程而是直接传参式调用对应封装接口完成调用具体代码如下图所示 此时从上述代码中我们就可以看出当我们使用头文件自己封装了一个Sock套接字类时下次我们无论是在客户端还是服务端中进行代码编写都可以直接包含该头文件直接使用类对象的方式进行传参式调用对应套接字通信接口再也不需要进行繁琐的失败/成功判断以及sockaddr_in结构体的初始化工作大大提高了我们的编码效率。并且值得注意的是要明白服务端建立连接会返回新的套接字而客户端不会本质是因为服务端需要确保多客户端同时访问而客户端不要所以客户端在进行网络通信时一直使用的都是唯一的套接字并不像服务端连接之后会有新的套接字供给其使用而从这一点出发此时我们需要明白创建套接字的本质除了是向系统申请网络通信请求以及资源之外更重要的是它还是对TCP缓冲区的一个抽象当然具体有关TCP缓冲区相关知识我们后续还会深入这里只要明白TCP缓冲区就是被接收数据和待发送数据的存储的空间就行。下述接着让我们回顾一下有关服务端和客户端之间通信的代码。 上述代码本质还是一份服务端通信代码我们重点想要回顾的就是服务端对多执行流的处理过程以及线程参数等问题的解决方式当然无论是多执行流还是线程参数等问题我们在之前的博客中都有详细介绍所以这里我们也不重点讲解我们的目标是搞定有关数据处理和返回接口也就是上述的server_io_task接口当然本质也就是因为该接口中的知识涉及的就是序列化和反序列化的知识所以此时让我们进入第二块知识一起来看看该接口中具体调用了那些头文件中的那些接口吧
第二块分析客户端和服务端中使用的头文件以及接口 搞定了上述有关套接字API的封装以及服务端多执行流和线程参数问题的回顾此时我们对服务端和客户端利用套接字进行网络通信又有了很好的认识所以此时我们就可以在此基础上对服务端和客户端进行进一步的理解当然也就是上述所说的有关数据接收处理和结果返回的知识server_io_task所以下面就让我们来看看服务端和客户端分别是如何对数据进行处理从而到达数据传输的可靠性和完整性。
首先是客户端 从上述代码中我们可以看出在实现网络版本计算机的基础上我们的客户端首先利用了我们自己封装好的Sock套接字API类实现了网络通信的基础然后又以行的形式获取到了我们自定义输入的计算表达式字符串然后对该计算表达式进行解析提取出它的左操作数、操作符和有操作数并将其赋值给Request结构体客户端请求结构体再然后客户端利用客户端请求结构体中的序列化接口将客户端请求数据序列化成某规定格式在序列化完成之后因为服务端从缓冲区进行数据读取方面的问题此时还需要对序列化数据加上一定的标识符当客户端将需发送数据序列化以及标示完成之后调用send接口发送给某指定服务器客户端传输工作全部完成。紧接着客户端只需要等待服务端响应结果数据然后对结果数据进行去报头和反序列化操作即可注此时的反序列化操作是与服务端响应数据结构体中的反序列化结构体挂钩。当然可想而知服务端传输数据和接收数据流程与客户端应该是大致相同的添加标示的原因也是相同的具体如下代码所示 从上述服务端代码我们可以看出服务端除了使用套接字实现网络通信和实现多执行流之外最重要的是它需要对客户端请求数据进行处理并且返回响应数据而在这个接收数据和返回数据的过程序列化和反序列化工作必不可少因为它可以让服务端和客户端在进行数据交互时保证数据的可靠性和完整性实现一种客户端初始化服务端直接读取的场景所以我们对传输数据进行序列化和反序列化本质就是想要实现该场景从而达到TCP协议所说的可靠传输。具体过程与客户端大致相同本质就是接收去标识反序列化逻辑处理获取结果对结果进行序列化和标识最终返回结果这里不过多赘述。目前我们需要解决的问题还有很多其中包括将结构化数据序列化成那种格式添加报头时如何标识以及添加标识的本质原因。所以为了解决这些问题此时就让我们一起来看看第三块知识的代码。
第三块规定结构化数据和序列化反序列化接口 在上述介绍什么是序列化和反序列化时我们谈到对于应用层而言它的本质就是将某种结构化数据转化为某种规定格式再由该规定格式转化为结构化数据的一个过程并且这个过程可以是按照自己的预期完成也可以是使用已经存在的标准序列化反序列化协议Json/Xml/Protocol Buffers完成而为了更加深入理解这块知识我们选择的是按照自己的预期来实现当然在自己实现之后我们会尝试使用Json标准进行序列化和反序列化工作。所以下述代码就是我们基于网络版本计算器场景下定制的一个服务端和客户端使用协议并且根据我们的预期和想法针对服务端和客户端数据需求的不同我们还分为了请求协议和响应协议本质也就是客户端使用的是请求协议的序列化过程而服务端使用的是请求协议的反序列化过程而因为服务端还需要将数据响应回客户端所以服务端还需要使用响应协议的序列化过程客户端使用响应协议的反序列化过程最终通过这样的方式让服务端和客户端双方都拿到自己想要的数据具体如下代码所示 此时通过对上述代码的编写我们就拥有了对客户端请求数据和服务端响应数据这两种结构化数据的序列化和反序列化的能力然后就只需要在对应的客户端对应的服务端中包含对应的头文件协议并且在合适的位置和时机下调用对应的接口我们就很好的构建出了一个客户端/服务端初始化结构化数据服务端/客户端直接读取数据的场景确保了数据传输的可靠性和完整性。当然本质上述代码因为我们规定序列化格式为字符串的形式所以在序列化和反序列化过程中进行的都是一系列的字符串操作具体我们不详谈然而对于我们来说更重要的是我们在将结构化数据序列化成字符串时对该字符串我们是可以进行格式控制的也就是说这个字符串最终是什么形式也是包含在协议定制当中的是受到规定的而恰好这一原理与我们添加报头也就是添加字符串标识是不谋而合的所以接下来我们就再看看传说中如何对序列化数据添加标识报头吧 如上述代码中所示此时我们就可以很好的为序列化数据和反序列化数据添加报头和去除报头当然同理上述所说添加报头的目的是为了便于recv接口向TCP缓冲区中读取数据时拥有读到完整数据的能力当然此时这个完整数据指的是预期服务端每次应该拿到的数据所以当我们对一个序列化数据添加报头之后服务端/客户端就可以根据该数据的报头获取到自己想要的数据也就是“完整数据”当然也就意味着该完整数据可以是不带报头的有效数据也可以是带有报头的组合数据总之就是要有依赖根据这个依赖读取到自己预期之中的完整数据如下代码所示 通过上述先读取报头中有效数据长度的方法我们就可以很好的将一个完整的预期报文从TCP缓冲区中读取出来避免了数据的不确定性和不完整性。但是此时我们会发现一个问题也就是为什么无论是服务端还是客户端在使用recv接口或者read接口从TCP缓冲区中读取数据都有可能会读取到不完整的数据呢本质原因非常简单因为当数据在进行网络传输时它需要满足网络协议栈的要求对发送数据包进行分片从而便于数据在网络中传输而因为数据包被分片那么此时就可能会因为网络问题导致部分数据片段被延迟或者是丢失从而导致接收数据不完整或者是不确定。所以当我们想要从TCP缓冲区中读取到特定预期数据时我们就需要使用报头的形式来进行标识。
使用Json标准协议完成序列化和反序列化工作
行文来到此处此时无论是序列化反序列化的概念、原理还是代码实现我们都有了一定的理解抛开客户端服务端通信方面的知识不谈单纯的从发送数据和接收数据来看序列化和反序列化并没有任何的难点值得注意的反而是如何根据报头从TCP缓冲区读取出完整的数据如何对数据进行格式控制和标识。所以上述无论是将结构化数据序列化成字符串的操作还是将序列化数据提取出来赋值给结构化变量的操作它本质是一个我们自定义的过程目的只是为了清楚序列化和反序列化的过程如何完成本质没有太大的作用。并且这个过程对于目前而言已经有非常多的标准供给我们使用所以下述我们就来看看Json的使用方式。 如上代码所示就是Json标准化协议的使用方式通过代码原理可以发现本质和我们自己实现序列化反序列化过程没有太大区别。上述自定义实现序列化和反序列化的工作以后我们就可以直接使用标准化协议直接代替不需要在麻烦的自己去定制协议以上就是有关序列化和反序列化的全部知识。
总结有关应用层序列化和反序列化相关的知识如上所述非常非常的详细啦See you。 ⭐好书推荐 《C从入门到精通》 【内容简介】
《C从入门到精通》从初学者的角度出发以通俗易懂的语言配合丰富的实例详细讲解了C语言的基础知识。 本书包括4篇18章第1篇是基础知识包括了绪论数据类型表达式与语句条件判断语句循环语句函数数组、指针和引用构造数据类型第2篇是核心技术包括了面向对象编程、类和对象、继承与派生第3篇是高级应用包括了模板、STL标准模板库、RTTI与异常处理、程序调测、文件操作、网络通信第4篇为项目实战结合图书管理系统依照软件工程的开发流程讲述如何进行实际开发。 京东购买链接【C从入门到精通】 当当购买链接【C从入门到精通】