网络通信应用层协议-序列化与反序列化

目录

1、序列化与反序列化概念

2、正、反序列化的目的

3、添加报头的目的 

4、实现正、反序列化思路

5、代码实现

6、添加报头、去除报头 

结语 


前言:

        在进行网络通信时,应用层协议是需要程序员手动定制的,序列化与反序列化是对协议进行字符串形式的转换。应用层协议表示发送端和接收端共同遵守的规则,依照这个规则,通信的双方才能够分析出传输数据的真正含义,只有理解了数据的真正含义,才能对数据进行处理,因此应用层协议在网络通信中非常重要。传输层协议为TPC\UDP,网络层协议为ipv4\ipv6,这些协议都是设置好的,而应用层协议需要程序员手动实现,传输应用层协议需要进行序列化与反序列化。 

1、序列化与反序列化概念

         序列化与反序列化是发送端和接收端对网络中传输数据的处理,是一种对传输数据的解释行为,通信双方制定好协议后,发送端需要将协议化的数据通过序列化传给接收端,而接收端拿到数据后需要对其进行反序列化以拿到协议的对应内容,具体示意图如下:

        如上图所示,序列化和反序列化实际上就是结构体->字符串,字符串->结构体的过程。

2、正、反序列化的目的

        反序列化的目的好理解,因为数据在传输前进行了正序列化,此时数据已经被“修饰”了,那么接收端必须采用同样的方式去掉“修饰”才能拿到有效数据,把这种行为叫做反序列化。那么为什么在传输数据前要将协议进行序列化呢?

        答:因为结构体类型在不同平台上的大小、存放形式不一样,因此不能直接将结构体传输给对方,并且结构体难以用字节流的形式在网络上传输。所以要进行序列化将其转换成字符串的形式传递。

3、添加报头的目的 

        上图中对协议内容进行添加报头,该行为的目的是为了接收方可以更好的解析序列化内容,还能够给在报头中进行数据加密,提供安全性。最主要的是若传输过程中出现数据丢失,则可以通过报头里的信息来判断是否发生数据丢失, 提供了数据在传输过程中的完整性。另外,还可以提供此次数据的版本号等等。

4、实现正、反序列化思路

        我们可以实现一个简单的计算机类,因为正反序列化是要在网络传输的过程中发挥作用的,为了能够更简单的描绘出正反序列化,所以我们在一个main函数中将整个过程模拟出来,方便理解。

        实现正、反序列化的思路:首先通信双方必须遵守同一个协议,即有同一个结构体类型,发送端发送的数据是由该结构体的成员变量进行序列化后再发送的,接收端拿到数据后先进行反序列化,然后添加到协议(结构体)里,此时说明接收端已经具备了处理数据的能力。如下图:

5、代码实现

        计算机类如下:

#pragma once

#include <iostream>
#include <string>
//用“ ”和“\n”表示协议的具体规定
const std::string blank_space_sep = " ";
const std::string protocol_sep = "\n";

class Request
{
public:
    Request(int data1, int data2, char oper) 
    : x(data1), y(data2), op(oper)
    {
    }
    Request()
    {
    }

public:
    bool Serialize(std::string *out)//序列化
    {
        // struct => string, "x op y"
        //根据协议的规定进行序列化
        std::string s = std::to_string(x);
        s += blank_space_sep;
        s += op;
        s += blank_space_sep;
        s += std::to_string(y);
        *out = s;
        return true;
    }
    bool Deserialize(const std::string &in) //反序列化
    {
        //根据协议的规定拿到有效数据
        std::size_t left = in.find(blank_space_sep);
        if (left == std::string::npos)
            return false;
        std::string part_x = in.substr(0, left);

        std::size_t right = in.rfind(blank_space_sep);
        if (right == std::string::npos)
            return false;
        std::string part_y = in.substr(right + 1);
        if (left + 2 != right)
            return false;
        //添加到当前的成员变量中
        op = in[left + 1];
        x = std::stoi(part_x);
        y = std::stoi(part_y);
        return true;
    }
    void DebugPrint()
    {
        std::cout << "新请求构建完成:  " << x << op << y << "=?" 
        << std::endl;
    }

public:
    // x op y
    int x;
    int y;
    char op; // + - * / %
};

         模拟序列化与反序列化的过程如下:

#include "app1.hpp"
#include <unistd.h>

int main(int argc, char *argv[])
{
    //模拟客户端序列化
    Request req(12364566, 43454356, '+');
    std::string s;
    req.Serialize(&s);
    std::cout << s <<std::endl;

    //模拟服务器反序列化
    Request temp;
    temp.Deserialize(s);
    temp.DebugPrint();

    
    return 0;
}

        运行结果:

6、添加报头、去除报头 

        添加报头的逻辑:将数据的长度作为报头的内容,并且用\n将报头内容与数据做分隔,这样接收端就可以根据第一个\n来拿到报头了。

        去除报头的逻辑:根据\n来拿到报头的内容,因为报头的内容是数据的长度,因此可以根据报头内容将数据从中取出。


         添加报头、去除报头的代码如下:

//添加报头:将数据长度作为报头内容,并用\n分隔开来
//(“len”\n"x op y"\n)
std::string Encode(std::string &content)
{
    std::string package = std::to_string(content.size());
    package += protocol_sep;
    package += content;
    package += protocol_sep;

    return package;
}
//根据报头内容以及\n,去掉报头,从而拿到数据本身
bool Decode(std::string &package, std::string *content)
{
    std::size_t pos = package.find(protocol_sep);
    if (pos == std::string::npos)//数据不完整,返回
        return false;
    std::string len_str = package.substr(0, pos);
    std::size_t len = std::stoi(len_str);
    std::size_t total_len = len_str.size() + len + 2;
    if (package.size() < total_len)//数据不完整,返回
        return false;

    *content = package.substr(pos + 1, len);
    // 走到此次说明数据正确被取出,因此package里的数据可以清空
    package.erase(0, total_len);

    return true;
}

        运行结果:

结语 

         以上就是关于网络通信应用层协议-序列化与反序列化的讲解,序列化与反序列化并不代码应用层协议本身,但是他与应用层协议密切相关,应用层协议是通信双方对传输的数据格式达成一致观念,而序列化与反序列化是进行数据传输的一种手段,他只一种行为。

        最后如果本文有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!! 

  • 20
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安权_code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值