网络通信的序列化和反序列化

news2024/12/25 2:07:31

序列化与反序列化的定义

由于在系统底层,数据的传输形式是简单的字节序列形式传递,即在底层,系统不认识对象,只认识字节序列,而为了达到进程通讯的目的,需要先将数据序列化,而序列化就是将对象转化字节序列的过程。相反地,当字节序列被运到相应的进程的时候,进程为了识别这些数据,就要将其反序列化,即把字节序列转化为对象

无论是在进程间通信、本地数据存储又或者是网络数据传输都离不开序列化的支持。而针对不同场景选择合适的序列化方案对于应用的性能有着极大的影响。

几种常见的序列化和反序列化协议

1 XML&SOAP

XML 是一种常用的序列化和反序列化协议,具有跨机器,跨语言等优点,SOAP(Simple Object Access protocol) 是一种被广泛应用的,基于 XML 为序列化和反序列化协议的结构化消息传递协议

2 JSON(Javascript Object Notation)

JSON 起源于弱类型语言 Javascript, 它的产生来自于一种称之为"Associative array"的概念,其本质是就是采用"Attribute-value"的方式来描述对象。实际上在 Javascript 和 PHP 等弱类型语言中,类的描述方式就是 Associative array。JSON 的如下优点,使得它快速成为最广泛使用的序列化协议之一。

这种 Associative array 格式非常符合工程师对对象的理解。

它保持了 XML 的人眼可读(Human-readable)的优点。

相对于 XML 而言,序列化后的数据更加简洁。 来自于的以下链接的研究表明:XML 所产生序列化之后文件的大小接近 JSON 的两倍

它具备 Javascript 的先天性支持,所以被广泛应用于 Web browser 的应用常景中,是 Ajax 的事实标准协议。

与 XML 相比,其协议比较简单,解析速度比较快。

松散的 Associative array 使得其具有良好的可扩展性和兼容性

3 Protobuf

Protobuf 具备了优秀的序列化协议的所需的众多典型特征。

标准的 IDL 和 IDL 编译器,这使得其对工程师非常友好。

序列化数据非常简洁,紧凑,与 XML 相比,其序列化之后的数据量约为 1/3 到 1/10。

解析速度非常快,比对应的 XML 快约 20-100 倍。

提供了非常友好的动态库,使用非常简介,反序列化只需要一行代码。

自己简单实现一个协议以及使用Json的小练习

Linux安装支持C++的Json库使用

sudo  yum  install  -y  jsoncpp-devel

protocal.hpp

#pragma once

#include<iostream>
#include<string>
#include<cstring>
#include<sys/types.h>
#include<sys/socket.h>
#include<jsoncpp/json/json.h>

using namespace std;


void enLen(string& s)
{
    string len = to_string(s.size());
    len += "\r\n";
    s = len + s;
}

void deLen(string& s)
{
    int n = s.find("\r\n");
    s = s.substr(n + strlen("\r\n"));   
}


class Requist
{
public:
    Requist(int ta = 0, int tb = 0, int top = 0)
    :a(ta), b(tb),op(top)
    {}
    string serialize()
    {
#ifdef MYSELF
        string s;
        s += to_string(a);
        s += " ";
        s += to_string(b);
        s += " ";
        s += op;
        s += "\r\n";
        return s;
#else
        Json::Value root;
        root["first"] = a;
        root["second"] = b;
        root["oper"] = op;
        Json::FastWriter writer;
        return writer.write(root);


#endif
    }

    bool reserialize(const string& s)
    {
#ifdef MYSELF
        auto left = s.find(" ");
        auto right = s.rfind(" ");
        if (left == std::string::npos || right == std::string::npos)
            return false;
        if (left == right)
            return false;
        if (right - (left + 1) != 1)
            return false;
        std::string x_string = s.substr(0, left); // [0, 2) [start, end) , start, end - start
        std::string y_string = s.substr(right + 1);

        if (x_string.empty())
            return false;
        if (y_string.empty())
            return false;
        a = std::stoi(x_string);
        b = std::stoi(y_string);
        op = s[left + 1];
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(s, root);
        a = root["first"].asInt();
        b = root["second"].asInt();
        op = root["oper"].asInt();
#endif
        return true;
    }

    int a;
    int b;
    char op;
};

class Respone
{
public:
    Respone(int exitcode = 0, int answer = 0)
    :_exitcode(exitcode), _answer(answer)
    {}
    string serialize()
    {
#ifdef MYSELF
        string s;
        s += to_string(_exitcode);
        s += " ";
        s += to_string(_answer);
        s += "\r\n";
        return s;
#else
        Json::Value root;
        Json::FastWriter writer;
        root["exitcode"] = _exitcode;
        root["answer"] = _answer;
        return writer.write(root);
#endif
    }
    void reserialize(const string& s)
    {
#ifdef MYSELF
        int n = s.find(" ");
        _exitcode = stoi(s.substr(0, n));
        int m = s.find("\r\n");
        _answer = stoi(s.substr(n + 1, m - n - 1));
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(s, root);
        _exitcode = root["exitcode"].asInt();
        _answer = root["answer"].asInt();

#endif
    }

    int _exitcode;
    int _answer;
};


bool recvPackage(int sock, string& inbuffer, string& text)
{
    char buffer[1024];
    while(true)
    {
        ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if(n > 0)
        {
            buffer[n] = 0;
            inbuffer += buffer;
            cout << inbuffer << endl;
            auto pos = inbuffer.find("\r\n");
            if (pos == std::string::npos)
                continue;
            std::string text_len_string = inbuffer.substr(0, pos);
            int text_len = std::stoi(text_len_string);
            int total_len = text_len_string.size() + strlen("\r\n") + text_len;
            if(total_len > inbuffer.size())
                continue;
            //cout << "111111111111" << endl;
            text = inbuffer.substr(0, total_len);
            inbuffer.erase(0, total_len);
            break;
            
        }
        else
            return false;

    }
    return true;
}

tcpClient.hpp

#include<iostream>
#include<string>
#include<cstring>
#include<stdlib.h>
#include<unistd.h>
#include<sstream>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"protocal.hpp"

using namespace std;

namespace szg
{
    class tcpClient
    {
    public:
        tcpClient(string ip, uint16_t port)
        :_ip(ip), _port(port)
        {
            _sock = socket(AF_INET, SOCK_STREAM, 0);
            if(_sock < 0)
            {
                cerr << "用户端创建套接字失败" << endl;
                exit(-1);
            }
            cout << "用户端创建套接字成功" << endl;
        }

        void start()
        {
            sockaddr_in server;
            server.sin_family = AF_INET;
            server.sin_port = htons(_port);
            server.sin_addr.s_addr = inet_addr(_ip.c_str());


            if(connect(_sock, (sockaddr*)&server, sizeof(server)))
            {
                cerr << "客户端获取服务失败" << endl;
            }
            cout << "客户端获取服务成功" << endl;


            while(true)
            {
                string message;
                while(true)
                {
                    getline(cin, message);
#ifdef MYSELF
                    message += "\r\n";
#else
                    Requist req;
                    std::istringstream iss(message);
                    iss >> req.a >> req.op >> req.b;
                    message = req.serialize();
#endif
                    enLen(message);
                    cout << "send:" << endl;
                    cout << message << endl;
                    send(_sock, message.c_str(), message.size(), 0);
                    

                    char rvbuf[1024];
                    size_t n = recv(_sock, rvbuf, sizeof(rvbuf) - 1, 0);
                    rvbuf[n] = 0;
                    string res_text = rvbuf;
                    cout << "res:" << endl;
                    cout << res_text << endl;
                    deLen(res_text);
                    Respone res;
                    res.reserialize(res_text);
                    if(0 == n)
                    {
                        cerr << "server qiut , me too" << endl;
                        break;
                    }
                    cout << "server 回显:" << endl;
                    cout << "exitcode:" << res._exitcode << endl;
                    cout << "answer:" << res._answer << endl;

                }
            }
        }

    private:
        int  _sock;
        string _ip;
        uint16_t _port;
    };



}

tcpServer.hpp

#include<iostream>
#include<string>
#include<cstring>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<map>
#include<functional>
#include"mythreadpool.hpp"
#include"log.hpp"
#include"protocal.hpp"

#include <string.h>
#include <errno.h>

using namespace std;

map<char, function<int(int, int)>> match{
    {'+', [](int a, int b){return a + b;}},
    {'-', [](int a, int b){return a - b;}},
    {'*', [](int a, int b){return a * b;}},
    {'/', [](int a, int b){return a / b;}},
    {'%', [](int a, int b){return a % b;}},
};

namespace szg
{

    class tcp_task
    {
        public:
        tcp_task(int sock = 0)
        :_sock(sock)
        {}

        void operator()()
        {
            char rdbuf[1024];
            string inbuffer;
            while (true)
            {
                string req_text;
                if(!recvPackage(_sock, inbuffer, req_text))
                {
                    cout << "recvPackage failed" << endl;
                    break;
                }
                else
                {
                    cout << "recvPackage success" << endl;
                    deLen(req_text);
                    //cout << req_text << endl;
                    Requist req;
                    Respone res;
                    if(req.reserialize(req_text))
                    {
                        if((req.op == '/' || req.op == '%') && req.b == 0)
                        {
                            res._exitcode = 0;
                        }
                        else
                        {
                            res._exitcode = 1;
                            res._answer = match[req.op](req.a, req.b);

                        }
                        string res_text = res.serialize();
                        cout << "res:" << res_text << endl;
                        enLen(res_text);
                        cout << "res:" << res_text << endl;
                        send(_sock, res_text.c_str(), res_text.size(), 0);
                    }
                    else
                        break;

                }
            }
            cout << _sock << ":exit"<< endl;
            close(_sock);
        }

        int _sock;
    };


    string df_ip = "0.0.0.0";
    uint16_t df_port = 8080;
    class tcpServer
    {
    public:
        tcpServer(uint16_t port = df_port)
        : _port(port)
        {
            //1.创建套接字
            _listensock = socket(AF_INET, SOCK_STREAM, 0);
            if(_listensock < 0)
            {
                cerr << "服务端创建套接字失败" << endl;
                exit(-1);
            }
            cout << "服务端创建套接字成功" << endl;

            logMessage(NORMAL, "accept a new link success, get new sock: %d", _listensock); // ?
            logMessage(DEBUG, "accept error, next");
            logMessage(WARNING, "accept error, next");
            logMessage(FATAL, "accept error, next");
            logMessage(NORMAL, "accept error, next");

            logMessage(NORMAL, "accept a new link success, get new sock: %d", _listensock); // ?
            logMessage(DEBUG, "accept error, next");
            logMessage(WARNING, "accept error, next");
            logMessage(FATAL, "accept error, next");
            logMessage(NORMAL, "accept error, next");

            logMessage(NORMAL, "accept a new link success, get new sock: %d", _listensock); // ?
            logMessage(DEBUG, "accept error, next");
            logMessage(WARNING, "accept error, next");
            logMessage(FATAL, "accept error, next");
            logMessage(NORMAL, "accept error, next");
        }

        void start()
        {
            //2.绑定套接字
            sockaddr_in server;
            memset(&server, 0, sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = htons(_port);
            server.sin_addr.s_addr = INADDR_ANY;
            if(-1 == bind(_listensock, (sockaddr*)&server, sizeof(server)))
            {
                cerr << "服务端绑定监听套接字失败" << endl;
                perror("server bind :");
                exit(1);
            }
            cout << "服务端绑定监听套接字成功" << endl;


            //3.设置套接字为监听状态
            if(listen(_listensock, 5))
            {
                cerr << "服务器监听状态设置失败" << endl;
                exit(2);
            }
            cout << "服务器监听状态设置成功" << endl;

            signal(SIGCHLD, SIG_IGN);


            
            while(true)
            {
                sockaddr_in peer;
                socklen_t len = sizeof(peer);

                //4.建立连接
                int newsock = accept(_listensock, (sockaddr*)&peer, &len);
                if(newsock < 0)
                {
                    cerr << "服务器监听客户端失败" << endl;
                }
                cout << "服务器监听客户端成功:" << newsock << endl;
                threadpool<tcp_task>::getinstance()->push(tcp_task(newsock));
                // if(0 == fork())
                // {
                //     char rdbuf[1024];
                //     while (true)
                //     {
                //         size_t n = read(newsock, rdbuf, sizeof(rdbuf) - 1);
                //         if(n == 0)
                //         {
                //             cout << "client offline,  me too" << endl;
                //             break;
                //         }
                //         rdbuf[n] = 0;
                        
                //         write(newsock, rdbuf, strlen(rdbuf));
                //     }
                //     exit(0);   
                // }
                // close(newsock);



            }
        }

    private:
        int  _listensock;
        uint16_t _port;
    };



}

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

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

相关文章

【SpringBoot_Project_Actual combat】 Summary of Project experience_需要考虑的问题

无论是初学者还是有经验的专业人士&#xff0c;在学习一门新的IT技术时&#xff0c;都需要采取一种系统性的学习方法。那么作为一名技术er&#xff0c;你是如何系统的学习it技术的呢。 一、DB Problems 数据库数据类型与java中数据类型对应问题&#xff1f; MySql数据库和java…

在Centos Stream 9上Docker的实操教程(一) - 实操准备篇

在Centos Stream 9上Docker的实操教程 - 实操准备篇 认识Docker准备Centos Stream 9安装Docker更新仓库绕不开的HelloWorld结语 认识Docker 什么都要实操了&#xff0c;你还不知道Docker是什么&#xff1f;网上关于Docker的介绍一搜一大把&#xff0c;博主就不必浪费时间去侃侃…

sqlserver行列转换( unpivot 和 pivot)

1&#xff0c;unpivot 是将列转为行显示&#xff0c;很多时候&#xff0c;我们用多个列了显示同一个对象不同维度得数据&#xff0c;如果需要数据关联&#xff0c;肯定需要转为横向显示&#xff01; 思路就是&#xff1a;有一列显示多列的名称&#xff0c;有一列显示列名对应的…

Redis发布订阅以及应用场景介绍

目录 一、什么是发布和订阅&#xff1f;二、Redis的发布和订阅三、发布和订阅的命令行实现四、发布和订阅命令1、subscribe&#xff1a;订阅一个或者多个频道2、publish&#xff1a;发布消息到指定的频道3、psubscribe&#xff1a;订阅一个或多个符合给定模式的频道4、pubsub&a…

通过facebook主页进行自己产品的推广可行吗?

首先&#xff0c;让我们明确结论&#xff1a;通过Facebook主页进行产品推广是可行的&#xff0c;但并不是必要的。为什么这么说呢&#xff1f; Facebook作为一个社交平台&#xff0c;其核心功能是连接人与人之间的关系&#xff0c;鼓励用户分享和互动。用户在Facebook上的活动主…

(学习日记)2023.04.23

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

实用可靠的安科瑞电动机保护控制器的应用

安科瑞 徐浩竣 江苏安科瑞电器制造有限公司 zx acrelxhj 摘要&#xff1a;介绍了一种新型电动机保护器&#xff0c;兼有电流、电压、过载、短路保护功能。它集电流型和电压型电动机保护器优点于一身&#xff0c;对电源欠电压、过电压、断相起闭锁作用&#xff0c;它结构简单…

【测试报告】个人博客系统自动化测试报告

文章目录 项目背景项目功能测试计划功能测试测试用例执行测试的操作步骤 自动化测试设计的模块、自动化运行的结果、问题定位的结果自动化测试优点 项目背景 对于一个程序员来说&#xff0c;定期整理总结并写博客是不可或缺的步骤&#xff0c;不管是对近期新掌握的技术或者是遇…

C# 读取json格式文件

读取json格式文件 安装 Newtonsoft.Json 程序集 1. 选择界面下方的【程序包管理器控制台】页面&#xff0c;输入安装指令 Install-Package Newtonsoft.Json 2. 安装完成后&#xff0c;请确保在代码文件的顶部包含以下 using 指令&#xff1a; using Newtonsoft.Json; 创建读…

GCC如何生成并调用静态库

一&#xff0c;简介 本文主要介绍如何使用gcc编译代码生成静态库&#xff0c;并调用静态库运行的操作步骤。 二&#xff0c;准备工作 使用add.c和main.c生成test可行性文件的流程图&#xff1a; add.c文件的内容&#xff1a; #include "add.h"int add(int a, i…

自学网络安全, 一般人我劝你还是算了吧

前言&#xff1a;自学我劝你还是算了&#xff0c;我为什么要劝你放弃我自己却不放弃呢&#xff1f;因为我不是一般人。。。 1.这是一条坚持的道路,三分钟的热情可以放弃往下看了. 2.多练多想,不要离开了教程什么都不会了.最好看完教程自己独立完成技术方面的开发. 3.有时多 …

【性能测试】Jenkins+Ant+Jmeter自动化框架的搭建思路

前言 前面讲了Jmeter在性能测试中的应用及扩展。随着测试的深入&#xff0c;我们发现在性能测试中也会遇到不少的重复工作。 比如某新兴业务处于上升阶段&#xff0c;需要在每个版本中&#xff0c;对某些新增接口进行性能测试&#xff0c;有时还需要在一天中的不同时段分别进行…

计算如何与实验结合发Science

理论计算与实验结合的研究已经成为TOP期刊中的主流方式。近日&#xff0c;上海交通大学种丽娜副教授一项关于质子交换膜水解槽阳极催化剂的研究成果在Science发表。该工作报道了一种由沸石甲基咪唑酯骨架&#xff08;Co-ZIF&#xff09;衍生并通过静电纺丝处理的镧和锰共掺杂的…

Python 修复共享内存问题和锁定共享资源问题

文章目录 使用 multiprocessing.Array() 在 Python 中使用共享内存解决多进程之间共享数据问题的解决方案 使用 multiprocessing.Lock() 锁定 Python 中的共享资源 本篇文章解释了多处理共享内存的不同方面&#xff0c;并演示了如何使用共享内存解决问题。 我们还将学习如何使用…

Axure教程—图片手风琴效果

本文将教大家如何用AXURE制作图片手风琴效果 一、效果介绍 如图&#xff1a; 预览地址&#xff1a;https://6nvnfm.axshare.com 下载地址&#xff1a;https://download.csdn.net/download/weixin_43516258/87847313?spm1001.2014.3001.5501 二、功能介绍 图片自动播放为手风…

MT4交易外汇平台有哪些优势?为何是外汇投资首选?

外汇市场上存在着各种各样的外汇交易商&#xff0c;但是很多的外汇交易商所选择的交易平台都是MT4交易外汇平台。作为全世界范围内使用最为广泛的交易平台&#xff0c;MT4交易外汇平台具有哪些优势&#xff0c;能够让外汇交易商和外汇投资者都选择使用。本文就来具体的聊聊&…

SQL中not in的一个坑

因not in 效率较低&#xff0c;在工作用一只用left join代替&#xff0c;在某一次查询使用了not in发现&#xff0c;结果为空&#xff0c;sql大致如下 select id from table1 where id not in (select id from table2)经过查询发现select id from table2里面的id有null值导致该…

司法大数据解决方案

2018年11月26日&#xff0c;司法部制定了《智慧监狱技术规范SFT0028-2018》并于2019年1月1日正式颁布实施&#xff0c;要求智慧监狱的建设应者眼于监狱工作实际&#xff0c;将物联网、云计算、大数据、人工智能等新一信息技术与监狱各项业务深度融合&#xff0c;形成标准规范科…

论文解读 | 基于改进点对特征的点云6D姿态估计

原创 | 文 BFT机器人 01 摘要 点对特征(PPF)方法已被证明是一种有效的杂波和遮挡下的姿态估计方法。 文章的改进方法主要包括: (1)一种基于奇偶规则求解封闭几何的法向的方法; (2)通过将体素网格划分为等效角度单元的有效降采样方法; (3)基于拟合点的验证步骤。在真实杂波数据集…

如何挖掘360下拉词,怎么删除360下拉负面词

大多数人的手机或者电脑上都安装了360浏览器&#xff0c;360搜索APP等&#xff0c;安装的用户量大&#xff0c;自然使用的用户也就多了&#xff0c;360下拉的优势就展现出来了&#xff0c;展示量大&#xff0c;全国各地均可见&#xff1b;能够引流来的都是相对精准的目标用户&a…