【Linux网络编程】序列化与反序列化

news2024/11/17 13:55:51

我们网络收发数据实际上只能接收到字符串,但是在现实生活中描述一个客观物体都是以很多属性来描述的,所以在网络中结构体类型的数据更常见,那我们如何发送结构体数据呢?

这里就涉及到协议的概念了。我们想象一个场景,在特种兵执行任务时,他们有特定的战术手语,这样他们就能根据手语进行相应的战术配合了。所以协议也是一样,客户端和服务器都遵循相同的协议,以某种格式把字符串变成结构体或把结构体变成字符串。这个过程中就是序列化与反序列化。

 序列化:结构体类型数据转化成字节序

反序列化:字节序转化成结构体类型数据

话不多说,看图

服务器利用套接字接收请求,进行反序列化后,对请求进行业务处理,处理完成把结果生成响应

然后序列化发送给客户端。自然,客户端接收响应也必须反序列化。

简易网络计算器协议协议部分代码:定制自己的协议,确定数据格式。

下面还利用到了Json这种数据转换格式语言。

#pragma once

#include <vector>
#include <string>
#include "Util.hpp"
#include <iostream>
#include <jsoncpp/json/json.h>
// 利用条件编译,在这里定义一个宏,如果定义了就走a,否则就走b,这相当于是一个开关

// #define HAHA 666
//  给网络版本计算器制定协议
namespace Protocol_ns
{

#define SEP " "
#define SEP_LEN strlen(SEP) // 不能用sizeof
#define HEADER_SEP "\r\n"
#define HEADER_SEP_LEN strlen("\r\n")

    // 请求/响应 = 报头\r\n有效载荷\r\n

    // "10 + 20" => "7"\r\n""10 + 20"\r\n
    std::string AddHeader(std::string &str)
    {
        std::string s = std::to_string(str.size());

        s += HEADER_SEP;
        s += str;
        s += HEADER_SEP;
        return s;
    }

    // 读取一个完整的报文;
    int ReadPackage(int sock, std::string &inbuffer, std::string *package)
    {

        char buffer[1024];
        ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0); // 读取
        if (n <= 0)
            return -1;
        buffer[n] = 0; // 添加字符串末尾'/0';
        inbuffer += buffer;

        size_t pos = inbuffer.find(HEADER_SEP);
        if (pos == std::string::npos)
            return 0; // 虽然读到了数据,但是不存在一个完整的报文,应该继续读取

        std::string lenStr = inbuffer.substr(0, pos);
        int len = Util::toInt(lenStr);
        int targetPackageLen = HEADER_SEP_LEN * 2 + len + lenStr.size();
        if (inbuffer.size() < targetPackageLen)
            return 0; // 虽然读到了数据,但是不存在一个完整的报文,应该继续读取

        *package = inbuffer.substr(0, targetPackageLen); // 提取到了整个报文
        inbuffer.erase(0, targetPackageLen);             // 从inbuffer中直接移除整个报文

        return len; // 返回有效载荷长度
    }

    // "7"\r\n""10 + 20"\r\n => "10 + 20"
    void RemoveHeader(std::string *package, int len)
    {
        size_t pos = (*package).find(HEADER_SEP);
        *package = (*package).erase(0, pos);

        *package = (*package).erase(0, HEADER_SEP_LEN);

        *package = (*package).substr(0, len);
    }

    // Request && Response都要提供序列化和反序列化功能
    class Request
    {
    public:
        Request() {}

        Request(int x, int y, char op)
            : _x(x), _y(y), _op(op)
        {
        }

        // struct -> string
        bool Serialization(std::string *outStr)
        {
            *outStr = "";
#ifdef HAHA

            std::string x_string = std::to_string(_x);
            std::string y_string = std::to_string(_y);

            // 手动序列化
            *outStr = x_string + SEP + _op + SEP + y_string; // outstr在这里是输出型参数;
#else
            Json::Value root; // Value: 一种万能对象, 接受任意的kv类型

            root["x"] = _x;
            root["y"] = _y;
            root["op"] = _op;

            Json::StyledWriter writer; // Writer是用来进行序列化的,struct->string
            *outStr = writer.write(root);

#endif
            return true;
        }

        // string->struct
        bool Deserialization(const std::string &inStr)
        {
#ifdef HAHA

            std::vector<std::string> result;
            Util::StringSplit(inStr, SEP, &result); // 对序列化数据进行分割,这相当于是一种解释;
            if (result.size() != 3)
                return false;
            if (result[1].size() != 1)
                return false;

            _x = Util::toInt(result[0]);
            _y = Util::toInt(result[2]);
            _op = result[1][0];
#else
            Json::Value root;
            Json::Reader reader; // Reader:用来进行反序列化的。

            reader.parse(inStr, root);
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _op = root["op"].asInt();

#endif
            return true;
        }

        ~Request() {}

    public:
        int _x;
        int _y;
        char _op;
    };

    class Response
    {
    public:
        Response() {}

        Response(int result, int code)
            : _result(result), _code(code)
        {
        }

        bool Serialization(std::string *outStr)
        {

            *outStr = "";
#ifdef HAHA
            std::string _result_string = std::to_string(_result);
            std::string _code_string = std::to_string(_code);

            // 手动序列化
            *outStr = _result_string + SEP + _code_string; // outstr在这里是输出型参数;

#else
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;

            Json::StyledWriter writer; // writer::用来进行序列化的;

            *outStr = writer.write(root);

#endif
            return true;
        }

        bool Deserialization(const std::string &inStr)
        {
#ifdef HAHA
            std::vector<std::string> result;
            Util::StringSplit(inStr, SEP, &result); // 对序列化数据进行分割,这相当于是一种解释;
            if (result.size() != 2)
                return false;

            _result = Util::toInt(result[0]);
            _code = Util::toInt(result[1]);
#else
            Json::Value root;
            Json::Reader reader;

            reader.parse(inStr,root);
            _result=root["result"].asInt();
            _code=root["code"].asInt();


#endif
            return true;
        }

        ~Response() {}

    public:
        int _result;
        int _code; // 0 success, 1,2,3,4代表不同的错误码;
    };
}

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

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

相关文章

MDK工程转换Vscode+EIDE方法

MDK工程转换VscodeEIDE方法 1、VscodeEIDE环境搭建方法 请按下方视频完成环境搭建&#xff0c;并编译成功。下载&#xff0c;单步调试如无视频中芯片可暂不执行。 https://www.bilibili.com/video/BV1Zu4y1f72H/?spm_id_from333.337.search-card.all.click&vd_source73…

Qt创建线程(继承于QThread的方法)

1.QThread&#xff1a; 继承QThread创建子线程的注意点&#xff1a; &#xff08;1&#xff09;需要写一个继承QThread的子类&#xff0c;然后必须要重写继承的run()函数&#xff08;在run函数里面重写要在线程中执行的方法&#xff08;任务函数&#xff09;&#xff09; &a…

STM32单片机中国象棋TFT触摸屏小游戏

实践制作DIY- GC0167-中国象棋 一、功能说明&#xff1a; 基于STM32单片机设计-中国象棋 二、功能介绍&#xff1a; 硬件组成&#xff1a;STM32F103RCT6最小系统2.8寸TFT电阻触摸屏24C02存储器1个按键&#xff08;悔棋&#xff09; 游戏规则&#xff1a; 1.有悔棋键&…

有没有免费的人才测评工具,免费的人才测评系统软件?

最近看到知乎上有个问题挺火的&#xff0c;就是问有没有免费的人才测评工具&#xff0c;人才测系统软件目前是有挺多的&#xff0c;但是要说免费&#xff0c;我还真心没有听说过&#xff0c;不但不免费&#xff0c;比较专业的人才测评公司&#xff0c;价格还是非常高的。 人才…

目标检测(Object Detection)概念速通

参考博文&#xff1a;目标检测&#xff08;Object Detection&#xff09;_YEGE学AI算法的博客-CSDN博客 这篇参考的相当多&#xff0c;写的真的很好很入门&#xff0c;觉得很有用&#xff0c;想详细了解的可以去看看&#xff0c;侵删↑ 上回组会分享了DETR和MDETR&#xff0c;…

【lesson9】进程

文章目录 什么是进程如何管理进程查看进程创建子进程 什么是进程 我们用一张Windows下的任务管理器图来辅助我们观看&#xff0c;我们一个可以看到应用在运行的时候就是一个个进程。 所以我们启动了一个软件本质上就是启动了一个进程。 在Linux下运行一条命令&#xff0c;./XXX…

探究Vcenter虚拟化方案中,VirtualMachine庞大结构体中各字段的含义

SDK中mo.VirtualMachine结构体定义如下: type VirtualMachine struct { ManagedEntity Capability types.VirtualMachineCapability mo:"capability" Config *types.VirtualMachineConfigInfo mo:"config" Layout …

十二、流程控制-循环

流程控制-循环 1.while循环语句★2.do...while语句★3.for循环语句 —————————————————————————————————————————————————— 1.while循环语句★ while语句也称条件判断语句&#xff0c;它的循环方式是利用一个条件来控制是否…

Spring实例化源码解析之ConfigurationClassPostProcessor(二)

ConfigurationClassPostProcessor源码 解析 书接上回&#xff0c;在第一次调用invokeBeanDefinitionRegistryPostProcessors方法的时候参数currentRegistryProcessors为ConfigurationClassPostProcessor&#xff0c;本章主要深入这个类的postProcessBeanDefinitionRegistry方法…

linux部署页面内容

/bin&#xff1a;该目录包含了常用的二进制可执行文件&#xff0c;如ls、cp、mv、rm等等。 /boot&#xff1a;该目录包含了启动Linux系统所需的文件&#xff0c;如内核文件和引导加载程序。 /dev&#xff1a;该目录包含了所有设备文件&#xff0c;如硬盘、光驱、鼠标、键盘等等…

LeetCode 刷题记录——从零开始记录自己一些不会的(二)

20. 替换后的最长重复字符 题意 给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符&#xff0c;并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。 在执行上述操作后&#xff0c;返回包含相同字母的最长子字符串的长度。 思路 代码 class Solution…

学习MLPERF

测试基准与标准 | BenchCouncil 其中涉及AI的有如下&#xff1a; AI (1) AIBench Training AIBench 培训采用平衡的 AI 基准测试方法&#xff0c;考虑全面性、代表性、可负担性和可移植性。该方法广泛调查人工智能任务和模型&#xff0c;并在最大程度上涵盖了算法级、系统级…

玩转YAML配置文件占位符 ,同事纷纷直呼大佬

配置文件占位符 Spring Boot配置文件支持占位符&#xff0c;一些用法如下&#xff1a; 为server.port设置一个随机端口 server: port: ${random.int} 其他随机占位符 // 随机数占位符${random.value} - 类似uuid的随机数&#xff0c;没有"-"连接${random.int} - 随…

【李沐深度学习笔记】矩阵计算(5)

课程地址和说明 线性代数实现p4 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 本节是第五篇&#xff0c;由于CSDN限制&#xff0c;只能被迫拆分 矩阵计算 多元函数的等高线 此处参考视频&#xff1a;熟肉)多元…

c语言-实用调试技巧

什么是bug&#xff1f; 程序中出现的问题 调试是什么&#xff1f;有多重要&#xff1f; 测试的基本步骤&#xff1a;发现程序错误的存在 以隔离、消除等方式对错误进行定位&#xff0c;确定错误产生的原因&#xff0c;提出纠正错误的解决办法&#xff0c;对程序错误予以改正…

【Servlet】第一个 Servlet 项目

第一个 Servlet 项目 一. Servlet 是什么二. Servlet 主要做的工作三. 第一个 Servlet 程序1. 创建项目2. 引入依赖3. 创建目录4. 编写代码5. 打包程序6. 部署程序7. 验证程序 四. 更方便的部署方式1. 安装 Smart Tomcat 插件2. 配置 Smart Tomcat 插件 一. Servlet 是什么 Se…

2023华为杯数学建模研赛思路分享——最全版本E题技术文档深度解析已出

2023华为杯数学建模研赛E题最新完整版技术文档已出 更多内容加群了解咨询【云顶数模科研交流群】&#xff1a; 正在跳转​qm.qq.com/cgi-bin/qm/qr?_wv1027&kzZ9YYiFSIhMwasovgcr-Fq6wp_ZF2-To&authKeyIDnk4VjKwk4FWcwTKW1ye8qfCOZjKbx%2FeLQVSFeD%2BrrUNJnhWAYwC%2…

OceanBase再获OSCAR两项大奖,坚定开源开放

2023 年 9 月 21 日&#xff0c;由中国信息通信研究院&#xff08;简称“中国信通院”&#xff09;、中国通信标准化协会联合主办的“OSCAR 开源产业大会”在京召开。本次发布了 2023 年可信开源评估结果&#xff0c;OceanBase 通过 可信开源 社区评估&#xff0c;荣获 “OSCAR…

【打开新世界大门】看测试老鸟如何把API 测试玩弄在鼓掌之间

【软件测试面试突击班】如何逼自己一周刷完软件测试八股文教程&#xff0c;刷完面试就稳了&#xff0c;你也可以当高薪软件测试工程师&#xff08;自动化测试&#xff09; 一、API 测试的基本步骤 我介绍过当今互联网产品的测试策略往往会采用菱形结构&#xff0c;即重量级 AP…

蜣螂优化(DBO)算法的5种最新变体(含MATLAB代码)

先做一个声明&#xff1a;文章是由我的个人公众号中的推送直接复制粘贴而来&#xff0c;因此对智能优化算法感兴趣的朋友&#xff0c;可关注我的个人公众号&#xff1a;启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法&#xff0c;经典的&#xff0c;或者是近几年…