国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

[計(jì)算機(jī)網(wǎng)絡(luò)]---序列化和反序列化

這篇具有很好參考價(jià)值的文章主要介紹了[計(jì)算機(jī)網(wǎng)絡(luò)]---序列化和反序列化。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

前言

[計(jì)算機(jī)網(wǎng)絡(luò)]---序列化和反序列化,網(wǎng)絡(luò),計(jì)算機(jī)網(wǎng)絡(luò)作者:小蝸牛向前沖

[計(jì)算機(jī)網(wǎng)絡(luò)]---序列化和反序列化,網(wǎng)絡(luò),計(jì)算機(jī)網(wǎng)絡(luò)名言:我可以接受失敗,但我不能接受放棄

??如果覺(jué)的博主的文章還不錯(cuò)的話,還請(qǐng)[計(jì)算機(jī)網(wǎng)絡(luò)]---序列化和反序列化,網(wǎng)絡(luò),計(jì)算機(jī)網(wǎng)絡(luò)點(diǎn)贊,收藏,關(guān)注??支持博主。如果發(fā)現(xiàn)有問(wèn)題的地方歡迎?大家在評(píng)論區(qū)指正?

目錄

?一、再談協(xié)議

二、序列化和反序化

1、網(wǎng)絡(luò)版本計(jì)算器的場(chǎng)景搭建

2、服務(wù)器構(gòu)建?

?3、客戶端構(gòu)建

4、序列化和反序列化?

4.1自定義序列化和反序列化

4.2json實(shí)現(xiàn)序列化和反序列化

?5、測(cè)試


本期學(xué)習(xí):重點(diǎn)理解序化和反序列化

?一、再談協(xié)議

? ? ? ? 在前面博客談網(wǎng)絡(luò)的時(shí)候,我們認(rèn)為協(xié)議就是一種約定,在用socket api接口的時(shí)候,都是按照“字符串”的方式來(lái)進(jìn)行發(fā)送和接受的,但是如果我們要傳輸一些結(jié)構(gòu)化的數(shù)據(jù),又該怎么辦?

這就要我們將數(shù)據(jù)序列化進(jìn)行傳輸或者接收。

在網(wǎng)絡(luò)通信中,傳輸結(jié)構(gòu)化數(shù)據(jù)的常見(jiàn)方法有以下幾種:

  1. 序列化: 將結(jié)構(gòu)化數(shù)據(jù)轉(zhuǎn)換為字符串或字節(jié)流進(jìn)行傳輸。在發(fā)送端,可以使用一種序列化格式將數(shù)據(jù)轉(zhuǎn)換為字符串或字節(jié)流;在接收端,再將接收到的字符串或字節(jié)流反序列化為相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。常見(jiàn)的序列化格式包括 JSON(JavaScript Object Notation)、XML(eXtensible Markup Language)、Protocol Buffers(protobuf)、MessagePack 等。選擇序列化格式時(shí),需要考慮數(shù)據(jù)的大小、可讀性、解析效率等因素。

  2. 數(shù)據(jù)格式協(xié)議: 使用一種規(guī)定的數(shù)據(jù)格式協(xié)議進(jìn)行數(shù)據(jù)傳輸。這種方法通常需要雙方預(yù)先約定好數(shù)據(jù)格式協(xié)議,并按照協(xié)議的規(guī)定進(jìn)行數(shù)據(jù)的編碼和解碼。常見(jiàn)的數(shù)據(jù)格式協(xié)議包括 HTTP、FTP、SMTP 等。在 HTTP 協(xié)議中,可以使用 Content-Type 來(lái)指定數(shù)據(jù)的格式,如 application/json 表示 JSON 格式數(shù)據(jù),application/xml 表示 XML 格式數(shù)據(jù)。

  3. 自定義協(xié)議: 自定義通信協(xié)議,定義數(shù)據(jù)的傳輸格式和規(guī)則。在自定義協(xié)議中,可以根據(jù)實(shí)際需求靈活地定義數(shù)據(jù)的結(jié)構(gòu)和編碼方式,以及通信過(guò)程中的規(guī)則和約定。自定義協(xié)議通常需要雙方進(jìn)行協(xié)商和實(shí)現(xiàn),但可以更好地滿足特定場(chǎng)景下的需求。

二、序列化和反序化

為了更好的理解,下面我們將通過(guò)自己定制tcp協(xié)議,將數(shù)據(jù)進(jìn)行序列化和反序列化。為了方便敘述,我們簡(jiǎn)單的制定網(wǎng)絡(luò)版本的計(jì)算 ,來(lái)理解協(xié)議中序列化和反序列化。

1、網(wǎng)絡(luò)版本計(jì)算器的場(chǎng)景搭建

我們的構(gòu)想是,客戶端通過(guò)將計(jì)算請(qǐng)求數(shù)據(jù)序列化,發(fā)送到網(wǎng)絡(luò)中,服務(wù)端接收后將數(shù)據(jù)進(jìn)行反序列化進(jìn)行計(jì)算處理。

[計(jì)算機(jī)網(wǎng)絡(luò)]---序列化和反序列化,網(wǎng)絡(luò),計(jì)算機(jī)網(wǎng)絡(luò)

處理過(guò)程大致如上圖:

  • c->s調(diào)用函數(shù)發(fā)送數(shù)據(jù)的本質(zhì)就是將一個(gè)緩沖區(qū)的拷貝到另外一個(gè)緩沖區(qū)。
  • s->c服務(wù)器回顯數(shù)據(jù)的本質(zhì)也是將s中緩沖區(qū)的數(shù)據(jù)拷貝到c中的緩沖區(qū)
  • 所以所tcp是全雙工的

2、服務(wù)器構(gòu)建?

這里構(gòu)建的服務(wù)器和上篇在套接字中的是沒(méi)有本質(zhì)區(qū)別的

#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include "log.hpp"
#include "protocol.hpp"
using namespace std;

namespace server
{
    enum
    {
        USAGE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR
    };

    static const uint16_t gport = 8080;
    static const int gbacklog = 5;
    // const Request &req: 輸入型
    // Response &resp: 輸出型
    typedef std::function<bool(const Request &req, Response &resp)> func_t;

    // 保證解耦
    void handlerEntery(int sock, func_t func)
    {
        std::string inbuffer;
        while (true)
        {
            // 1. 讀?。?content_len"\r\n"x op y"\r\n
            // 1.1 你怎么保證你讀到的消息是 【一個(gè)】完整的請(qǐng)求
            std::string req_text, req_str;
            // 1.2 我們保證,我們r(jià)eq_text里面一定是一個(gè)完整的請(qǐng)求:"content_len"\r\n"x op y"\r\n
            if (!recPackage(sock, inbuffer, &req_text))
                return;
            std::cout << "帶報(bào)頭的請(qǐng)求:\n"
                      << req_text << std::endl;
            if (!deLength(req_text, &req_str))
                return;
            std::cout << "去掉報(bào)頭的正文:\n"
                      << req_str << std::endl;

            // 2. 對(duì)請(qǐng)求Request,反序列化
            // 2.1 得到一個(gè)結(jié)構(gòu)化的請(qǐng)求對(duì)象
            Request req;
            if (!req.deserialize(req_str))
                return;

            // 3. 計(jì)算機(jī)處理,req.x, req.op, req.y --- 業(yè)務(wù)邏輯
            // 3.1 得到一個(gè)結(jié)構(gòu)化的響應(yīng)
            Response resp;
            func(req, resp); // req的處理結(jié)果,全部放入到了resp, 回調(diào)是不是不回來(lái)了?不是!

            // 4.對(duì)響應(yīng)Response,進(jìn)行序列化
            // 4.1 得到了一個(gè)"字符串"
            std::string resp_str;
            resp.serialize(&resp_str);

            std::cout << "計(jì)算完成, 序列化響應(yīng): " << resp_str << std::endl;

            // 5. 然后我們?cè)诎l(fā)送響應(yīng)
            // 5.1 構(gòu)建成為一個(gè)完整的報(bào)文
            std::string send_string = enLength(resp_str);
            send(sock, send_string.c_str(), send_string.size(), 0); // 其實(shí)這里的發(fā)送也是有問(wèn)題的,不過(guò)后面再說(shuō)
        }
    }

    class CalServer
    {
    public:
        CalServer(const uint16_t &port = gport) : _listensock(-1), _port(port)
        {
        }
        void initServer()
        {
            // 1. 創(chuàng)建socket文件套接字對(duì)象
            _listensock = socket(AF_INET, SOCK_STREAM, 0);
            if (_listensock < 0)
            {
                logMessage(FATAL, "create socket error");
                exit(SOCKET_ERR);
            }
            logMessage(NORMAL, "create socket success: %d", _listensock);

            // 2. bind綁定自己的網(wǎng)絡(luò)信息
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = INADDR_ANY;
            if (bind(_listensock, (struct sockaddr *)&local, sizeof(local)) < 0)
            {
                logMessage(FATAL, "bind socket error");
                exit(BIND_ERR);
            }
            logMessage(NORMAL, "bind socket success");

            // 3. 設(shè)置socket 為監(jiān)聽(tīng)狀態(tài)
            if (listen(_listensock, gbacklog) < 0) // 第二個(gè)參數(shù)backlog后面在填這個(gè)坑
            {
                logMessage(FATAL, "listen socket error");
                exit(LISTEN_ERR);
            }
            logMessage(NORMAL, "listen socket success");
        }
        void start(func_t func)
        {
            for (;;)
            {
                // 4. server 獲取新鏈接
                // sock, 和client進(jìn)行通信的fd
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                int sock = accept(_listensock, (struct sockaddr *)&peer, &len);
                if (sock < 0)
                {
                    logMessage(ERROR, "accept error, next");
                    continue;
                }
                logMessage(NORMAL, "accept a new link success, get new sock: %d", sock); // ?

                // version 2 多進(jìn)程版(2)
                pid_t id = fork();
                if (id == 0) // child
                {
                    close(_listensock);
                    // if(fork()>0) exit(0);
                    //  serviceIO(sock);
                    handlerEntery(sock, func);
                    close(sock);
                    exit(0);
                }
                close(sock);

                // father
                pid_t ret = waitpid(id, nullptr, 0);
                if (ret > 0)
                {
                    logMessage(NORMAL, "wait child success"); // ?
                }
            }
        }
        ~CalServer() {}

    private:
        int _listensock; // 不是用來(lái)進(jìn)行數(shù)據(jù)通信的,它是用來(lái)監(jiān)聽(tīng)鏈接到來(lái),獲取新鏈接的!
        uint16_t _port;
    };
}

對(duì)于?handlerEntery這個(gè)操作我們要分析,在這函數(shù)中首先我們要獲取到由客戶端發(fā)送過(guò)來(lái)的報(bào)文,而客戶端發(fā)送過(guò)來(lái)的報(bào)文肯定是經(jīng)過(guò)序列化的,所以我們要進(jìn)行反序列化,在通過(guò)func回調(diào)函數(shù)得到一個(gè)結(jié)構(gòu)化的響應(yīng),在將響應(yīng)通過(guò)處理發(fā)送給客戶端。

 // 保證解耦
    void handlerEntery(int sock, func_t func)
    {
        std::string inbuffer;
        while (true)
        {
            // 1. 讀取:"content_len"\r\n"x op y"\r\n
            // 1.1 你怎么保證你讀到的消息是 【一個(gè)】完整的請(qǐng)求
            std::string req_text, req_str;
            // 1.2 我們保證,我們r(jià)eq_text里面一定是一個(gè)完整的請(qǐng)求:"content_len"\r\n"x op y"\r\n
            if (!recPackage(sock, inbuffer, &req_text))
                return;
            std::cout << "帶報(bào)頭的請(qǐng)求:\n"
                      << req_text << std::endl;
            if (!deLength(req_text, &req_str))
                return;
            std::cout << "去掉報(bào)頭的正文:\n"
                      << req_str << std::endl;

            // 2. 對(duì)請(qǐng)求Request,反序列化
            // 2.1 得到一個(gè)結(jié)構(gòu)化的請(qǐng)求對(duì)象
            Request req;
            if (!req.deserialize(req_str))
                return;

            // 3. 計(jì)算機(jī)處理,req.x, req.op, req.y --- 業(yè)務(wù)邏輯
            // 3.1 得到一個(gè)結(jié)構(gòu)化的響應(yīng)
            Response resp;
            func(req, resp); // req的處理結(jié)果,全部放入到了resp, 回調(diào)是不是不回來(lái)了?不是!

            // 4.對(duì)響應(yīng)Response,進(jìn)行序列化
            // 4.1 得到了一個(gè)"字符串"
            std::string resp_str;
            resp.serialize(&resp_str);

            std::cout << "計(jì)算完成, 序列化響應(yīng): " << resp_str << std::endl;

            // 5. 然后我們?cè)诎l(fā)送響應(yīng)
            // 5.1 構(gòu)建成為一個(gè)完整的報(bào)文
            std::string send_string = enLength(resp_str);
            send(sock, send_string.c_str(), send_string.size(), 0); // 其實(shí)這里的發(fā)送也是有問(wèn)題的,不過(guò)后面再說(shuō)
        }
    }

對(duì)于calServer.cc的主程序,就是簡(jiǎn)單進(jìn)行cal計(jì)算業(yè)務(wù)?

#include "calServer.hpp"
#include <memory>

using namespace server;
using namespace std;

static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
// req: 里面一定是我們的處理好的一個(gè)完整的請(qǐng)求對(duì)象
// resp: 根據(jù)req,進(jìn)行業(yè)務(wù)處理,填充resp,不用管理任何讀取和寫(xiě)入,序列化和反序列化等任何細(xì)節(jié)
bool cal(const Request &req, Response &resp)
{
    // req已經(jīng)有結(jié)構(gòu)化完成的數(shù)據(jù)啦,你可以直接使用
    resp._exitcode = OK;
    resp._result = OK;

    switch (req._op)
    {
    case '+':
        resp._result = req._x + req._y;
        break;
    case '-':
        resp._result = req._x - req._y;
        break;
    case '*':
        resp._result = req._x * req._y;
        break;
    case '/':
    {
        if (req._y == 0)
            resp._exitcode = DIV_ZERO;
        else
            resp._result = req._x / req._y;
    }
    break;
    case '%':
    {
        if (req._y == 0)
            resp._exitcode = MOD_ZERO;
        else
            resp._result = req._x % req._y;
    }
    break;
    default:
        resp._exitcode = OP_ERROR;
        break;
    }

    return true;
}

// tcp服務(wù)器,啟動(dòng)上和udp server一模一樣
// ./tcpserver local_port
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);

    unique_ptr<CalServer> tsvr(new CalServer(port));
    tsvr->initServer();
    tsvr->start(cal);
    return 0;
}

?3、客戶端構(gòu)建

對(duì)于客戶端calClinet.hpp完成的主要邏輯是進(jìn)行連網(wǎng),輸入計(jì)算,對(duì)服務(wù)器進(jìn)行計(jì)算請(qǐng)求,在進(jìn)行計(jì)算信息的構(gòu)建。?

#pragma once

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

#define NUM 1024
using namespace std;
class CalClient
{
public:
    CalClient(const std::string &serverip, const uint16_t &serverport)
        : _sock(-1), _serverip(serverip), _serverport(serverport)
    {
    }
    void initClient()
    {
        // 1. 創(chuàng)建socket
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_sock < 0)
        {
            std::cerr << "socket create error" << std::endl;
            exit(2);
        }
        // 2. tcp的客戶端要不要bind?要的! 要不要顯示的bind?不要!這里尤其是client port要讓OS自定隨機(jī)指定!
        // 3. 要不要listen?不要!
        // 4. 要不要accept? 不要!
        // 5. 要什么呢??要發(fā)起鏈接!
    }
    void start()
    {
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_serverport);
        server.sin_addr.s_addr = inet_addr(_serverip.c_str());

        if (connect(_sock, (struct sockaddr *)&server, sizeof(server)) != 0)
        {
            std::cerr << "socket connect error" << std::endl;
        }
        else
        {
            std::string line;
            std::string inbuffer;
            while (true)
            {
                std::cout << "mycal>>> ";
                // 輸入計(jì)算
                getline(cin, line);
                // 進(jìn)行請(qǐng)求
                Request req = ParseLine(line);
                string content; // 存放計(jì)算信息
                req.serialize(&content);
                string send_string = enLength(content); // 添加報(bào)頭
                send(_sock, send_string.c_str(), send_string.size(), 0);

                string package, text;
                if (!recPackage(_sock, inbuffer, &package))
                    continue;
                if (!deLength(package, &text))
                    continue;

                // 響應(yīng)
                Response resp;
                resp.deserialize(text);
                std::cout << "exitCode: " << resp._exitcode << std::endl;
                std::cout << "result: " << resp._result << std::endl;
            }
        }
    }
    // 從文本中提取計(jì)算格式信息,然后用這些信息構(gòu)建請(qǐng)求
    Request ParseLine(const std::string &line)
    {
        //"1+1" "123*456" "12/0"
        int status = 0; // 0:操作符之前,1:碰到了操作符 2:操作符之后
        int i = 0;
        int cnt = line.size();
        string left, right;
        char op;
        while (i < cnt)
        {
            switch (status)
            {
            case 0:
            {
                if (!isdigit(line[i])) // isdigit檢查字符是否是十進(jìn)制
                {
                    op = line[i];
                    status = 1;
                }
                else
                    left.push_back(line[i++]);
            }
            break;
            case 1:
            {
                i++;
                status = 2;
            }
            break;
            case 2:
            {
                right.push_back(line[i++]);
            }
            break;
            }
        }
        std::cout << std::stoi(left) << " " << std::stoi(right) << " " << op << std::endl;
        return Request(std::stoi(left), std::stoi(right), op);
    }
    ~CalClient()
    {
        if (_sock >= 0)
            close(_sock);
    }

private:
    int _sock;
    std::string _serverip;
    uint16_t _serverport;
};

calClient.cc?

#include "calClient.hpp"
#include <memory>

using namespace std;

static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " serverip serverport\n\n";
}
// ./tcpclient serverip serverport
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    string serverip = argv[1];
    uint16_t serverport = atoi(argv[2]);

    unique_ptr<CalClient> tcli(new CalClient(serverip, serverport));
    tcli->initClient();
    tcli->start();
    return 0;
}

4、序列化和反序列化?

4.1自定義序列化和反序列化

前面說(shuō)了一大堆要對(duì)數(shù)據(jù)進(jìn)行序列化和反序列化 ,那到底什么是序列化和反序列,其實(shí)本質(zhì)就是將一堆字符串,整和成一個(gè)字符串。為了完成我們網(wǎng)絡(luò)計(jì)算器,這里我們寫(xiě)了二個(gè)類(lèi),一個(gè)是?Request對(duì)數(shù)據(jù)進(jìn)行請(qǐng)求,另外一個(gè)是Response,每個(gè)類(lèi)中都要對(duì)序化和反序列進(jìn)行設(shè)計(jì)

class Request
{
public:
    Request() : _x(0), _y(0), _op(0)
    {
    }
    Request(int x, int y, char op) : _x(x), _y(y), _op(op)
    {
    }
    // 1. 自己寫(xiě)
    // 2. 用現(xiàn)成的
    bool serialize(std::string *out)
    {
    }
    // "x op yyyy";
    bool deserialize(const std::string &in)
    {
    }
public:
    // "x op y"
    int _x;
    int _y;
    char _op;
};

// 響應(yīng)
class Response
{
public:
    Response() : _exitcode(0), _result(0)
    {
    }
    Response(int exitcode, int result) : _exitcode(exitcode), _result(result)
    {
    }
    bool serialize(std::string *out)
    {

    }
    bool deserialize(const std::string &in)
    {

    }

public:
    int _exitcode; // 0:計(jì)算成功,!0表示計(jì)算失敗,具體是多少,定好標(biāo)準(zhǔn)
    int _result;   // 計(jì)算結(jié)果
};

其中序列化和反序列化可以自己進(jìn)行編寫(xiě),也可以通過(guò)庫(kù)進(jìn)行完成。

在大部分場(chǎng)景中我們都是用json進(jìn)行序列結(jié)構(gòu)的,對(duì)于自定義序列化,每個(gè)實(shí)現(xiàn)方式可能不同,所以不重點(diǎn)分析了,下面會(huì)有完整代碼,大家可以參考實(shí)現(xiàn)

4.2json實(shí)現(xiàn)序列化和反序列化

在Linux上使用json我們要進(jìn)行庫(kù)的安裝

sudo yum install -y jsoncpp-devel

[計(jì)算機(jī)網(wǎng)絡(luò)]---序列化和反序列化,網(wǎng)絡(luò),計(jì)算機(jī)網(wǎng)絡(luò)

序列化?

使用了 JsonCpp 庫(kù)來(lái)創(chuàng)建一個(gè) JSON 對(duì)象 root,然后將一些值 _x_y_op 分別存儲(chǔ)到 JSON 對(duì)象的鍵 "first"、"second""oper" 中。接下來(lái),使用 Json::FastWriter 對(duì)象 writer 來(lái)將 JSON 對(duì)象 root 轉(zhuǎn)換為字符串,并將結(jié)果寫(xiě)入到 out 指向的位置。

 Json::Value root;
        root["first"] = _x;
        root["second"] = _y;
        root["oper"] = _op;

        Json::FastWriter writer;
        // Json::StyledWriter writer;
        *out = writer.write(root);

反序列化?

?使用了 JsonCpp 庫(kù)來(lái)解析輸入的 JSON 字符串 in,并將解析得到的值存儲(chǔ)到 Json::Value 類(lèi)型的對(duì)象 root 中。然后,通過(guò)訪問(wèn) root 對(duì)象的鍵 "first""second""oper" 來(lái)獲取相應(yīng)的值,并將這些值轉(zhuǎn)換為整數(shù)類(lèi)型,并分別存儲(chǔ)到 _x、_y_op 變量中。

 Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        _x = root["first"].asInt();
        _y = root["second"].asInt();
        _op = root["oper"].asInt();

?注意:asInt() 函數(shù)用于將 JSON 值轉(zhuǎn)換為整數(shù)類(lèi)型

protocol.hpp?完整代碼實(shí)現(xiàn):添加報(bào)文,去報(bào)頭,請(qǐng)求,響應(yīng)獲取數(shù)據(jù)包

#pragma once

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

#define SEP " "
#define SEP_LEN strlen(SEP)
#define LINE_SEP "/r/n" // /r回車(chē)   /n換行   /r/n表示換行的同時(shí)將光標(biāo)移動(dòng)到行首
#define LINE_SEP_LEN strlen(LINE_SEP)
using namespace std;

// 錯(cuò)誤枚舉
enum
{
    OK = 0,
    DIV_ZERO,
    MOD_ZERO,
    OP_ERROR
};
// "x op y" -> "content_len"\r\n"x op y"\r\n
// "exitcode result" -> "content_len"\r\n"exitcode result"\r\n

// 添加報(bào)頭
string enLength(string &text)
{
    string send_string = to_string(text.size());
    send_string += LINE_SEP;
    send_string += text;
    send_string += LINE_SEP;

    return send_string;
}
// 去報(bào)頭
//  "content_len"\r\n"exitcode result"\r\n
bool deLength(const std::string &package, std::string *text)
{
    auto pos = package.find(LINE_SEP);
    if (pos == string::npos)
        return false;
    string text_len_string = package.substr(0, pos);
    int text_len = stoi(text_len_string);
    *text = package.substr(pos + LINE_SEP_LEN, text_len);
    return true;
}

// 請(qǐng)求
class Request
{
public:
    Request() : _x(0), _y(0), _op(0)
    {
    }
    Request(int x, int y, char op) : _x(x), _y(y), _op(op)
    {
    }
    // 1. 自己寫(xiě)
    // 2. 用現(xiàn)成的
    bool serialize(std::string *out)
    {
#ifdef MYSELF
        *out = "";
        // 結(jié)構(gòu)化 -> "x op y";
        std::string x_string = std::to_string(_x);
        std::string y_string = std::to_string(_y);

        *out = x_string;
        *out += SEP;
        *out += _op;
        *out += SEP;
        *out += y_string;
#else
        Json::Value root;
        root["first"] = _x;
        root["second"] = _y;
        root["oper"] = _op;

        Json::FastWriter writer;
        // Json::StyledWriter writer;
        *out = writer.write(root);
#endif
        return true;
    }

    // "x op yyyy";
    bool deserialize(const std::string &in)
    {
#ifdef MYSELF
        // "x op y" -> 結(jié)構(gòu)化
        auto left = in.find(SEP);
        auto right = in.rfind(SEP);
        if (left == std::string::npos || right == std::string::npos)
            return false;
        if (left == right)
            return false;
        if (right - (left + SEP_LEN) != 1)
            return false;

        std::string x_string = in.substr(0, left); // [0, 2) [start, end) , start, end - start
        std::string y_string = in.substr(right + SEP_LEN);

        if (x_string.empty())
            return false;
        if (y_string.empty())
            return false;
        _x = std::stoi(x_string);
        _y = std::stoi(y_string);
        _op = in[left + SEP_LEN];
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        _x = root["first"].asInt();
        _y = root["second"].asInt();
        _op = root["oper"].asInt();
#endif
        return true;
    }

public:
    // "x op y"
    int _x;
    int _y;
    char _op;
};

// 響應(yīng)
class Response
{
public:
    Response() : _exitcode(0), _result(0)
    {
    }
    Response(int exitcode, int result) : _exitcode(exitcode), _result(result)
    {
    }
    bool serialize(std::string *out)
    {
#ifdef MYSELF
        *out = "";
        std::string ec_string = std::to_string(_exitcode);
        std::string res_string = std::to_string(_result);

        *out = ec_string;
        *out += SEP;
        *out += res_string;
#else
        Json::Value root;
        root["exitcode"] = _exitcode;
        root["result"] = _result;

        Json::FastWriter writer;
        *out = writer.write(root);
#endif
        return true;
    }
    bool deserialize(const std::string &in)
    {
#ifdef MYSELF
        // "exitcode result"
        auto mid = in.find(SEP);
        if (mid == std::string::npos)
            return false;
        std::string ec_string = in.substr(0, mid);
        std::string res_string = in.substr(mid + SEP_LEN);
        if (ec_string.empty() || res_string.empty())
            return false;

        _exitcode = std::stoi(ec_string);
        _result = std::stoi(res_string);
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        _exitcode = root["exitcode"].asInt();
        _result = root["result"].asInt();
#endif
        return true;
    }

public:
    int _exitcode; // 0:計(jì)算成功,!0表示計(jì)算失敗,具體是多少,定好標(biāo)準(zhǔn)
    int _result;   // 計(jì)算結(jié)果
};

// 獲取數(shù)據(jù)包
//  "content_len"\r\n"x op y"\r\n"content_len"\r\n"x op y"\r\n"content_len"\r\n"x op
bool recPackage(int sock, string &inbuffer, string *text)
{
    char buffer[1024];
    while (true)
    {
        // 從網(wǎng)絡(luò)中接受資源
        ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            inbuffer += buffer;

            // 分析
            auto pos = inbuffer.find(LINE_SEP);
            if (pos == string::npos)
                continue;
            string text_len_string = inbuffer.substr(0, pos);
            int text_len = stoi(text_len_string);
            // 報(bào)文的總長(zhǎng)度
            int total_len = text_len_string.size() + 2 * LINE_SEP_LEN + text_len;
            // text_len_string + "\r\n" + text + "\r\n" <= inbuffer.size();
            std::cout << "處理前#inbuffer: \n"
                      << inbuffer << std::endl;

            if (inbuffer.size() < total_len)
            {
                std::cout << "你輸入的消息,沒(méi)有嚴(yán)格遵守我們的協(xié)議,正在等待后續(xù)的內(nèi)容, continue" << std::endl;
                continue;
            }
            // 最少一個(gè)完整報(bào)文
            *text = inbuffer.substr(0, total_len);
            inbuffer.erase(0, total_len);

            std::cout << "處理后#inbuffer:\n " << inbuffer << std::endl;

            break;
        }
        else
            return false;
    }
    return true;
}

?5、測(cè)試

下面我們進(jìn)行幾組簡(jiǎn)單的測(cè)試:

[計(jì)算機(jī)網(wǎng)絡(luò)]---序列化和反序列化,網(wǎng)絡(luò),計(jì)算機(jī)網(wǎng)絡(luò)

?左邊是服務(wù)器,又邊上是客戶端[計(jì)算機(jī)網(wǎng)絡(luò)]---序列化和反序列化,網(wǎng)絡(luò),計(jì)算機(jī)網(wǎng)絡(luò)

Linux小命令

killall 是一個(gè)在 Unix 和類(lèi) Unix 操作系統(tǒng)上用于終止進(jìn)程的命令。與 kill 命令不同,killall 不是根據(jù)進(jìn)程 ID(PID)來(lái)終止進(jìn)程,而是根據(jù)進(jìn)程的名稱(chēng)來(lái)匹配并終止相應(yīng)的進(jìn)程。

killall [選項(xiàng)] 進(jìn)程名

其中,選項(xiàng)可以用來(lái)指定不同的操作行為,而進(jìn)程名則是要終止的進(jìn)程的名稱(chēng)。

一些常用的選項(xiàng)包括:

  • -e:顯示詳細(xì)的錯(cuò)誤信息。
  • -i:交互模式,在終止進(jìn)程之前詢問(wèn)用戶。
  • -q:安靜模式,不顯示任何輸出。
  • -u:指定用戶,僅終止指定用戶的進(jìn)程。

注意:killall 命令會(huì)終止所有匹配名稱(chēng)的進(jìn)程,因此需要謹(jǐn)慎使用,以免意外終止系統(tǒng)中重要的進(jìn)程

?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-830228.html

到了這里,關(guān)于[計(jì)算機(jī)網(wǎng)絡(luò)]---序列化和反序列化的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Linux】TCP網(wǎng)絡(luò)套接字編程+協(xié)議定制+序列化和反序列化

    【Linux】TCP網(wǎng)絡(luò)套接字編程+協(xié)議定制+序列化和反序列化

    悟已往之不諫,知來(lái)者之可追。抓不住的就放手,屬于你的都在路上…… 1. 為了讓我們的代碼更規(guī)范化,所以搞出了日志等級(jí)分類(lèi),常見(jiàn)的日志輸出等級(jí)有DEBUG NORMAL WARNING ERROR FATAL等,再配合上程序運(yùn)行的時(shí)間,輸出的內(nèi)容等,公司中就是使用日志分類(lèi)的方式來(lái)記錄程序的輸

    2024年02月08日
    瀏覽(25)
  • 什么是序列化和反序列化?

    JSON(JavaScript Object Notation)和XML(eXtensible Markup Language)是兩種常用的數(shù)據(jù)交換格式,用于在不同系統(tǒng)之間傳輸和存儲(chǔ)數(shù)據(jù)。 JSON是一種輕量級(jí)的數(shù)據(jù)交換格式,它使用易于理解的鍵值對(duì)的形式表示數(shù)據(jù)。JSON數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單明了,易于讀寫(xiě)和解析,是基于JavaScript的一種常用數(shù)據(jù)

    2024年02月09日
    瀏覽(29)
  • Unity-序列化和反序列化

    序列化是指把對(duì)象轉(zhuǎn)換為字節(jié)序列的過(guò)程,而反序列化是指把字節(jié)序列恢復(fù)為對(duì)象的過(guò)程。序列化最主要的用途就是傳遞對(duì)象和保存對(duì)象。 在Unity中保存和加載、prefab、scene、Inspector窗口、實(shí)例化預(yù)制體等都使用了序列化與反序列化。 1 自定義的具有Serializable特性的非抽象、

    2024年01月24日
    瀏覽(27)
  • Java序列化和反序列化

    目錄 一、序列化和反序列化 二、Java序列化演示 三、反序列化漏洞 1、含義 ?序列化就是內(nèi)存中的對(duì)象寫(xiě)入到IO流中,保存的格式可以是二進(jìn)制或者文本內(nèi)容。反序列化就是IO流還原成對(duì)象。 2、用途 (1)傳輸網(wǎng)絡(luò)對(duì)象 (2)保存Session 1、序列化 java.io.ObjectOutputStream代表對(duì)象

    2023年04月25日
    瀏覽(24)
  • 【Linux】序列化和反序列化

    【Linux】序列化和反序列化

    在網(wǎng)絡(luò)編程中,直接使用 結(jié)構(gòu)體 進(jìn)行數(shù)據(jù)傳輸會(huì)出錯(cuò),因?yàn)?本質(zhì)上socket無(wú)法傳輸結(jié)構(gòu)體 ,我們只有將結(jié)構(gòu)體裝換為字節(jié)數(shù)組,或者是字符串格式來(lái)傳輸,然后對(duì)端主機(jī)收到了數(shù)據(jù),再將其轉(zhuǎn)化為結(jié)構(gòu)體,這就是序列化和反序列化的過(guò)程! 序列化 (Serialization)是將對(duì)象的狀態(tài)

    2024年02月10日
    瀏覽(19)
  • Java序列化和反序列化機(jī)制

    在閱讀 ArrayList 源碼的時(shí)候,注意到,其內(nèi)部的成員變量動(dòng)態(tài)數(shù)組 elementData 被Java中的 transient 修飾 transient 意味著Java在序列化時(shí)會(huì)跳過(guò)該字段(不序列化該字段) 而Java在默認(rèn)情況下會(huì)序列化類(lèi)(實(shí)現(xiàn)了 Java.io.Serializable 接口的類(lèi))的所有非瞬態(tài)(未被 transient 修飾

    2024年03月15日
    瀏覽(27)
  • jackjson自定義序列化和反序列化

    jackjson自定義序列化和反序列化

    JRT引用的jackjson作為json處理庫(kù)。由于JRT.ORM要求表不用datetime類(lèi)型,把日期和時(shí)間用Int存儲(chǔ),所以O(shè)RM要支持日期時(shí)間的轉(zhuǎn)換。為什么要把日期時(shí)間不用datetime而用Int,比如日期:20240117,時(shí)間就是從0點(diǎn)到當(dāng)前的秒數(shù)。因?yàn)椴挥胐atetime兼容性好,不會(huì)因?yàn)椴煌瑤?kù)datetime函數(shù)不同而要

    2024年01月18日
    瀏覽(21)
  • TCP定制協(xié)議,序列化和反序列化

    TCP定制協(xié)議,序列化和反序列化

    目錄 前言 1.理解協(xié)議 2.網(wǎng)絡(luò)版本計(jì)算器 2.1設(shè)計(jì)思路 2.2接口設(shè)計(jì) 2.3代碼實(shí)現(xiàn): 2.4編譯測(cè)試 總結(jié) ? ? ? ? 在之前的文章中,我們說(shuō)TCP是面向字節(jié)流的,但是可能對(duì)于面向字節(jié)流這個(gè)概念,其實(shí)并不理解的,今天我們要介紹的是如何理解TCP是面向字節(jié)流的,通過(guò)編碼的方式,自

    2024年02月12日
    瀏覽(23)
  • java中的序列化和反序列化

    objectOutputStream 對(duì)象的序列化,以流的形式將對(duì)象寫(xiě)入文件 構(gòu)造方法: objectOutputStream(OutputStream out) 傳入一個(gè)字節(jié)輸入流創(chuàng)建objectOutputStream對(duì)象 成員方法: void writeObject(object obj) 將指定的對(duì)象寫(xiě)入objectOutputStream 使用步驟: 創(chuàng)建一個(gè)類(lèi),這個(gè)類(lèi)實(shí)現(xiàn)Serializable接口,Serializable是一

    2024年02月14日
    瀏覽(19)
  • Java中序列化和反序列化解釋

    在Java中,序列化(Serialization)是指將對(duì)象的狀態(tài)轉(zhuǎn)換為字節(jié)流的過(guò)程,以便將其保存到文件、在網(wǎng)絡(luò)中傳輸或持久化到數(shù)據(jù)庫(kù)中。而反序列化(Deserialization)則是將字節(jié)流轉(zhuǎn)換回對(duì)象的過(guò)程,恢復(fù)對(duì)象的狀態(tài)。 序列化和反序列化主要用于以下場(chǎng)景: 1. 對(duì)象持久化:通過(guò)序列

    2024年02月07日
    瀏覽(23)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包