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

序列化与反序列化的定义

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

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

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

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;
    };



}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JDSZGLLL

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

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

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

打赏作者

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

抵扣说明:

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

余额充值