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

【Linux后端服務(wù)器開發(fā)】協(xié)議定制(序列化與反序列化)

這篇具有很好參考價值的文章主要介紹了【Linux后端服務(wù)器開發(fā)】協(xié)議定制(序列化與反序列化)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

一、應(yīng)用層協(xié)議概述

二、序列化與反序列化

Protocal.h頭文件

Server.h頭文件

Client.h頭文件

server.cpp源文件

client.cpp源文件


一、應(yīng)用層協(xié)議概述

什么是應(yīng)用層?我們通過編寫程序解決一個個實際問題、滿足我們?nèi)粘P枨蟮木W(wǎng)絡(luò)程序,都是應(yīng)用層程序。

協(xié)議是一種“約定”,socket的api接口,在讀寫數(shù)據(jù)時,都是按“字符串”的方式發(fā)送數(shù)據(jù),那么如果我們要傳輸一些“結(jié)構(gòu)化的數(shù)據(jù)”怎么辦?

這時就需要用到應(yīng)用層協(xié)議,一端將結(jié)構(gòu)化數(shù)據(jù)轉(zhuǎn)化成字符串格式,另一端通過協(xié)議的“約定”格式,將其解析成結(jié)構(gòu)化數(shù)據(jù)。

應(yīng)用層協(xié)議的本質(zhì),就是對傳輸層的字符串數(shù)據(jù)進行序列化和反序列化,使結(jié)構(gòu)化數(shù)據(jù)可以進行網(wǎng)絡(luò)通信。

雖然應(yīng)用層協(xié)議是程序員根據(jù)不同的程序進行定制的,但實際上,已經(jīng)有大佬定義了很多現(xiàn)成又非常好用的應(yīng)用層協(xié)議,供我們直接參考使用,例如?HTTP / HTTPS(超文本傳輸協(xié)議)

URL:我們俗稱的“網(wǎng)址”,其實就是URL,例如https://blog.csdn.net/phoenixFlyzzz?type=blog

這是我的博客主頁網(wǎng)址的url,每個url都是有固定格式的,通過特殊符號分隔:

  • https:// —— 協(xié)議方案名
  • blog.csdn.net —— 服務(wù)器域名
  • /phoenixFlyzzz —— 帶層次的文件路徑
  • ?type=blog —— 參數(shù)

在這個URL中,并沒有完全展示一個網(wǎng)址的全部結(jié)構(gòu),但一個URL也不是一定有全部結(jié)構(gòu)的,有些結(jié)構(gòu)可以省略,有些結(jié)構(gòu)不寫會有默認值。

urlencodeurldecode:url的編碼和解碼,像 / ? : 這些字符,已經(jīng)被URL當作特殊字符處理了,用于區(qū)分一個URL中不同的結(jié)構(gòu)字段,因此這些字符不能隨意出現(xiàn)。如果某個參數(shù)中需要用到這種特殊字符,比必須先對特殊字符進行轉(zhuǎn)義。

轉(zhuǎn)義的規(guī)則:將需要轉(zhuǎn)碼的字符轉(zhuǎn)為16進制數(shù),然后從左到右,取4位(不足4位直接處理)每2位做一位,前面加上%,編碼成%XY格式。

例如,“+”被轉(zhuǎn)義成“%2B”:

【Linux后端服務(wù)器開發(fā)】協(xié)議定制(序列化與反序列化),Linux后端服務(wù)器開發(fā),服務(wù)器,運維,網(wǎng)絡(luò)

urldecode就是urlencode的逆過程,將轉(zhuǎn)義過的字符進行解碼。

二、序列化與反序列化

設(shè)計:通過TCP協(xié)議定制一個網(wǎng)絡(luò)計算器,客戶端發(fā)送算式,服務(wù)器返回結(jié)果

算法:復雜算式的運算規(guī)則、字符串數(shù)據(jù)序列化與反序列化、Json數(shù)據(jù)解析

由于用到了Json庫,需要在編譯的時候加上 -ljsoncpp

Protocal.h頭文件

網(wǎng)絡(luò)計算器的協(xié)議定制(序列化與反序列化),定義請求體和響應(yīng)體的對象,請求體與響應(yīng)體對象在數(shù)據(jù)傳輸過程中都需要進行序列化和反序列化操作

  • 序列化:將輸入的數(shù)據(jù)轉(zhuǎn)換成規(guī)定格式的字符串
  • 反序列化:將規(guī)定格式的字符串轉(zhuǎn)化成結(jié)構(gòu)化數(shù)據(jù)
#pragma once

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

using namespace std;

#define SEP " "
#define LINE_SEP "\r\n"

enum
{
    OK = 0,
    DIV_ZERO,
    MOD_ZERO,
    OP_ERR
};

// "x op y" -> "content_len"\r\n"x op y"\r\n
string En_Length(const string& text)
{
    string send_str = to_string(text.size());
    send_str += LINE_SEP;
    send_str += text;
    send_str += LINE_SEP;

    return send_str;
}

// "content_len"\r\n"x op y"\r\n
bool De_Length(const string& package, string* text)
{
    auto pos = package.find(LINE_SEP);
    if (pos == string::npos)
        return false;
    string text_len_str = package.substr(0, pos);
    int text_len = stoi(text_len_str);
    *text = package.substr(pos + strlen(LINE_SEP), text_len);
    return true;
}

// 通信協(xié)議不止一種,需要將協(xié)議進行編號,以供os分辨
// "content_len"\r\n"協(xié)議編號"\r\n"x op y"\r\n

class Request
{
public:
    Request(int x = 0, int y = 0, char op = 0)
        : _x(x), _y(y), _op(op)
    {}

    // 序列化
    bool Serialize(string* out)
    {
    #ifdef MYSELF
        *out = "";

        // 結(jié)構(gòu)化 -> "x op y"
        string x_str = to_string(_x);
        string y_str = to_string(_y);

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

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

    // 反序列化
    bool Deserialiaze(const string& in)
    {
    #ifdef MYSELF
        // "x op y" -> 結(jié)構(gòu)化
        auto left = in.find(SEP);
        auto right = in.rfind(SEP);

        if (left == string::npos || right == string::npos)
            return false;
        if (left == right)
            return false;
        if (right - (left + strlen(SEP)) != 1)
            return false;
        
        string x_str = in.substr(0, left);
        string y_str = in.substr(right + strlen(SEP));

        if (x_str.empty() || y_str.empty())
            return false;
        
        _x = stoi(x_str);
        _y = stoi(y_str);
        _op = in[left + strlen(SEP)];
    #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:
    int _x, _y;
    char _op;
};

class Response
{
public:
    Response(int exitcode = 0, int res = 0)
        : _exitcode(exitcode), _res(res)
    {}

    bool Serialize(string* out)
    {
    #ifdef MYSELF
        *out = "";
        string ec_str = to_string(_exitcode);
        string res_str = to_string(_res);

        *out = ec_str;
        *out += SEP;
        *out += res_str;
    #else
        Json::Value root;
        root["exitcode"] = _exitcode;
        root["result"] = _res;

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

    bool Deserialize(const string& in)
    {
    #ifdef MYSELF
        auto mid = in.find(SEP);
        if (mid == string::npos)
            return false;

        string ec_str = in.substr(0, mid);
        string res_str = in.substr(mid + strlen(SEP));
        if (ec_str.empty() || res_str.empty())
            return false;

        _exitcode = stoi(ec_str);
        _res = stoi(res_str);
    #else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

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

public:
    int _exitcode;
    int _res;
};

// 讀取數(shù)據(jù)包
// "content_len"\r\n"x op y"\r\n
bool Recv_Package(int sock, string& inbuf, string* text)
{
    char buf[1024];
    while (true)
    {
        ssize_t n = recv(sock, buf, sizeof(buf) - 1, 0);
        if (n > 0)
        {
            buf[n] = 0;
            inbuf += buf;

            auto pos = inbuf.find(LINE_SEP);
            if (pos == string::npos)
                continue;
            string text_len_str = inbuf.substr(0, pos);
            int text_len = stoi(text_len_str);
            int total_len = text_len_str.size() + 2 * strlen(LINE_SEP) + text_len;
            cout << "處理前#inbuf:\n" << inbuf << endl;

            if (inbuf.size() < total_len)
            {
                cout << "輸入不符合協(xié)議規(guī)定" << endl;
                continue;
            }

            *text = inbuf.substr(0, total_len);
            inbuf.erase(0, total_len);
            cout << "處理后#inbuf:\n" << inbuf << endl;

            break;
        }
        else
        {
            return false;
        }
    }

    return true;
}

// 計算任務(wù)
bool Cal(const Request& req, Response& resp)
{
    resp._exitcode = OK;
    resp._res = 0;

    if (req._op == '/' && req._y == 0)
    {
        resp._exitcode = DIV_ZERO;
        return false;
    }
    if (req._op == '%' && req._y == 0)
    {
        resp._exitcode = MOD_ZERO;
        return false;
    }

    switch (req._op)
    {
    case '+':
        resp._res = req._x + req._y;
        break;
    case '-':
        resp._res = req._x - req._y;
        break;
    case '*':
        resp._res = req._x * req._y;
        break;
    case '/':
        resp._res = req._x / req._y;
        break;
    case '%':
        resp._res = req._x % req._y;
        break;
    default:
        resp._exitcode = OP_ERR;
        break;
    }

    return true;
}

Server.h頭文件

網(wǎng)絡(luò)計算器的服務(wù)器,讀取請求體報文,執(zhí)行計算任務(wù),生成響應(yīng)體報文

#pragma once

#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <functional>
#include <sys/wait.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "Protocal.h"

using namespace std;
using func_t = function<bool(const Request& req, Response& resp)>;

const static uint16_t g_port = 8080;
const static int g_backlog = 5;

void Handler_Entry(int sock, func_t func)
{
    string inbuf;
    while (true)
    {
        // 1. 讀取報文: "content_len"\r\n"x op y"\r\n
        string req_text, req_str;
        if (!Recv_Package(sock, inbuf, &req_text))
            return;
        cout << "帶報頭的請求:\n" << req_text << endl;
        if (!De_Length(req_text, &req_str))
            return;
        cout << "去報頭的正文:\n" << req_str << endl;

        // 2. 對請求Request反序列化,得到結(jié)構(gòu)化請求對象
        Request req;
        if (!req.Deserialiaze(req_str))
            return;
        
        // 3. 業(yè)務(wù)邏輯, 生成結(jié)構(gòu)化響應(yīng)
        Response resp;
        func(req, resp);    // 處理req,生成resp

        // 4. 對相應(yīng)的Response序列化
        string resp_str;
        resp.Serialize(&resp_str);
        cout << "計算完成,序列化響應(yīng):\n" << resp_str << endl;

        // 5. 構(gòu)建完整報文,發(fā)送響應(yīng)
        string send_str = En_Length(resp_str);
        cout << "構(gòu)建完整的響應(yīng)報文:\n" << send_str << endl;
        send(sock, send_str.c_str(), send_str.size(), 0);
    }
}

class Server
{
public:
    Server(const int port)
        : _port(port), _listenfd(-1)
    {}

    void Init()
    {
        _listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listenfd < 0)
            exit(1);

        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = htonl(INADDR_ANY);
        local.sin_port = htons(_port);

        if (bind(_listenfd, (struct sockaddr*)&local, sizeof(local)) < 0)
            exit(1);

        if (listen(_listenfd, g_backlog) < 0)
            exit(1);
    }

    void Start(func_t func)
    {
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t peer_len = sizeof(peer);
            int sock = accept(_listenfd, (struct sockaddr*)&peer, &peer_len);
            if (sock < 0)
                exit(1);
            
            pid_t id = fork();
            if (id == 0)
            {
                close(_listenfd);
                Handler_Entry(sock, func);
                close(sock);
                exit(0);
            }
            pid_t ret = waitpid(id, nullptr, 0);
        }
    }

private:
    int _listenfd;
    uint16_t _port;
};

Client.h頭文件

客戶端頭文件,通過輸入數(shù)據(jù)生產(chǎn)請求體,將服務(wù)器返回的響應(yīng)體序列化和反序列化文章來源地址http://www.zghlxwxcb.cn/news/detail-602861.html

#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "Protocal.h"

using namespace std;

class Client
{
public:
    Client(const std::string& server_ip, const uint16_t& server_port)
        : _sock(-1), _server_ip(server_ip), _server_port(server_port)
    {}

    void Init()
    {
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_sock < 0)
        {
            std::cerr << "socket error" << std::endl;
            exit(1);
        }
    }

    void Run()
    {
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_server_port);
        server.sin_addr.s_addr = inet_addr(_server_ip.c_str());

        if (connect(_sock, (struct sockaddr*)&server, sizeof(server)) < 0)
        {
            std::cerr << "connect error" << std::endl;
            exit(1);
        }
        else
        {
            string line;
            string inbuf;
            while (true)
            {
                cout << "mycal>>> ";
                getline(cin, line);
                Request req = Parse_Line(line);     // 輸入字符串,生成Request對象

                string content;
                req.Serialize(&content);                // Request對象序列化
                string send_str = En_Length(content);   // 序列化字符串編碼 -> "content_len"\r\n"x op y"\r\n
                send(_sock, send_str.c_str(), send_str.size(), 0);

                // 將服務(wù)器的返回結(jié)果序列化與反序列化
                string package, text;
                if (!Recv_Package(_sock, inbuf, &package))
                    continue;
                if (!De_Length(package, &text))
                    continue;
                
                Response resp;
                resp.Deserialize(text);
                cout << "exitcode: " << resp._exitcode << endl;
                cout << "result: " << resp._res << endl << endl;
            }
        }
    }

    // 將輸入轉(zhuǎn)化為Request結(jié)構(gòu)
    Request Parse_Line(const string& line)
    {
        int status = 0;     // 0:操作符之前    1:遇到操作符    2:操作符之后
        int cnt = line.size();
        string left, right;
        char op;
        int i = 0;
        while (i < cnt)
        {
            switch (status)
            {
            case 0:
                if (!isdigit(line[i]))
                {
                    if (line[i] == ' ')
                    {
                        i++;
                        break;
                    }
                    op = line[i];
                    status = 1;
                }
                else
                {
                    left.push_back(line[i++]);
                }
                break;
            case 1:
                i++;
                if (line[i] == ' ')
                    break;
                status = 2;
                break;
            case 2:
                right.push_back(line[i++]);
                break;
            }
        }
        cout << left << ' ' << op << ' ' << right << endl;
        return Request(stoi(left), stoi(right), op);
    }

    ~Client()
    {
        if (_sock >= 0)
            close(_sock);
    }

private:
    int _sock;
    string _server_ip;
    uint16_t _server_port;
};

server.cpp源文件

#include "Server.h"
#include <memory>

void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " local_port\n\t";
    exit(1);
}

// ./server port
int main(int argc, char* argv[])
{
    if (argc != 2)
        Usage(argv[0]);

    uint16_t port = atoi(argv[1]);

    std::unique_ptr<Server> tsvr(new Server(port));
    tsvr->Init();
    tsvr->Start(Cal);

    return 0;
}

client.cpp源文件

#include "Client.h"
#include <memory>

using namespace std;

static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
    exit(1);
}

int main(int argc, char* argv[])
{
    if (argc != 3)
        Usage(argv[0]);

    string server_ip = argv[1];
    uint16_t server_port = atoi(argv[2]);

    unique_ptr<Client> tcli(new Client(server_ip, server_port));
    tcli->Init();
    tcli->Run();

    return 0;
}

到了這里,關(guān)于【Linux后端服務(wù)器開發(fā)】協(xié)議定制(序列化與反序列化)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

  • 【Linux后端服務(wù)器開發(fā)】基礎(chǔ)IO與文件系統(tǒng)

    【Linux后端服務(wù)器開發(fā)】基礎(chǔ)IO與文件系統(tǒng)

    目錄 一、基礎(chǔ)IO 1. C語言文件讀寫 2. 標志位傳參 3. C語言與系統(tǒng)調(diào)用關(guān)系 二、文件系統(tǒng) 1. 文件描述符 2. 輸入輸出重定向 文件調(diào)用 庫函數(shù)接口: fopen、fclose、fwrite、fread、fseek 系統(tǒng)調(diào)用接口:open、close、write、read、lseek r/w/a :讀/寫/追加 若打開的文件不存在,“r”報錯,“

    2024年02月15日
    瀏覽(23)
  • 【Linux后端服務(wù)器開發(fā)】封裝線程池實現(xiàn)TCP多線程通信

    目錄 一、線程池模塊 Thread.h LockGuard.h ThreadPool.h 二、任務(wù)模塊模塊 Task.h 三、日志模塊 Log.h 四、守護進程模塊 Deamon.h ?五、TCP通信模塊 Server.h Client.h server.cpp client.cpp 關(guān)于TCP通信協(xié)議的封裝,此篇博客有詳述: 【Linux后端服務(wù)器開發(fā)】TCP通信設(shè)計_命運on-9的博客-CSDN博客 線程池

    2024年02月16日
    瀏覽(25)
  • 強推Linux高性能服務(wù)器編程, 真的是后端開發(fā)技術(shù)提升, 沉淀自身不容錯過的一本經(jīng)典書籍

    強推Linux高性能服務(wù)器編程, 真的是后端開發(fā)技術(shù)提升, 沉淀自身不容錯過的一本經(jīng)典書籍

    目錄 第1章 TCP/IP協(xié)議 1.1 TCP/IP協(xié)議族體系結(jié)構(gòu)以及主要協(xié)議 1.1.1 數(shù)據(jù)鏈路層 1.1.2 網(wǎng)絡(luò)層 1.1.3 傳輸層 1.1.4 應(yīng)用層 1.2 封裝 1.3 分用 1.5 ARP協(xié)議工作原理 1.5.1 以太網(wǎng)ARP請求/應(yīng)答報文詳解 1.5.2 ARP高速緩存的查看和修改 1.5.3 使用tcpdump觀察ARP通信過程所得結(jié)果如下 本篇核心關(guān)鍵所在

    2024年02月07日
    瀏覽(100)
  • 【Linux】TCP網(wǎng)絡(luò)套接字編程+協(xié)議定制+序列化和反序列化

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

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

    2024年02月08日
    瀏覽(24)
  • 談?wù)刲inux網(wǎng)絡(luò)編程中的應(yīng)用層協(xié)議定制、Json序列化與反序列化那些事

    談?wù)刲inux網(wǎng)絡(luò)編程中的應(yīng)用層協(xié)議定制、Json序列化與反序列化那些事

    由于socket api的接口,在讀寫數(shù)據(jù)的時候是以字符串的方式發(fā)送接收的,如果需要傳輸 結(jié)構(gòu)化的數(shù)據(jù) ,就需要制定一個協(xié)議 結(jié)構(gòu)化數(shù)據(jù)在發(fā)送到網(wǎng)絡(luò)中之前需要完成序列化 接收方收到的是序列字節(jié)流,需要完成反序列化才能使用(如ChatInfo._name) 當我們進行網(wǎng)絡(luò)通信的的時

    2024年02月06日
    瀏覽(25)
  • 【音視頻開發(fā)】:RTSP服務(wù)器協(xié)議內(nèi)容

    【音視頻開發(fā)】:RTSP服務(wù)器協(xié)議內(nèi)容

    RTSP是一個 實時傳輸流協(xié)議 ,是一個 應(yīng)用層 的協(xié)議。通常說的RTSP包括RTSP協(xié)議、RTP協(xié)議、RTCP協(xié)議。 RTSP協(xié)議:負責服務(wù)器與客戶端之間的請求與相應(yīng) RTP協(xié)議 :負責服務(wù)器與客戶端之間傳輸媒體數(shù)據(jù) RTCP協(xié)議:負責提供有關(guān)RTP傳輸指令的反饋,就是確保RTP傳輸?shù)馁|(zhì)量 吧 三者關(guān)

    2024年04月26日
    瀏覽(27)
  • Flask框架小程序后端分離開發(fā)學習筆記《2》構(gòu)建基礎(chǔ)的HTTP服務(wù)器

    Flask框架小程序后端分離開發(fā)學習筆記《2》構(gòu)建基礎(chǔ)的HTTP服務(wù)器

    Flask是使用python的后端,由于小程序需要后端開發(fā),遂學習一下后端開發(fā)。本節(jié)提供一個構(gòu)建簡單的本地服務(wù)器的代碼,仔細看注釋,學習每一步的流程,理解服務(wù)器接收請求,回復響應(yīng)的基本原理。 代碼效果,運行之后,在瀏覽器輸入:localhost:2000 總結(jié) 1.導入socket庫:這個庫

    2024年01月18日
    瀏覽(24)
  • Flask框架小程序后端分離開發(fā)學習筆記《4》向服務(wù)器端發(fā)送模擬請求-爬蟲

    Flask是使用python的后端,由于小程序需要后端開發(fā),遂學習一下后端開發(fā)。 下面代碼,是一個比較老的版本了,可以借鑒一下。 最后嘗試請求豆瓣的網(wǎng)頁,并未得到,我懷疑是有反爬手段,我們的請求數(shù)據(jù)還有很多東西沒加進去,所以看起來不像是瀏覽器發(fā)送的請求,后續(xù)會

    2024年01月20日
    瀏覽(28)
  • 如何在linux服務(wù)器上用Nginx部署Vue項目,以及如何部署springboot后端項目

    如何在linux服務(wù)器上用Nginx部署Vue項目,以及如何部署springboot后端項目

    提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔 提示:這里可以添加本文要記錄的大概內(nèi)容: 本文內(nèi)容記錄如何在Linux(Ubuntu)系統(tǒng)上安裝Nginx,并部署打包好的Vue前端項目,最后通過瀏覽器訪問。 提示:以下是本篇文章正文內(nèi)容,下面案例可供參考

    2024年04月16日
    瀏覽(31)
  • 【網(wǎng)絡(luò)】協(xié)議定制+序列化/反序列化

    【網(wǎng)絡(luò)】協(xié)議定制+序列化/反序列化

    如果光看定義很難理解序列化的意義,那么我們可以從另一個角度來推導出什么是序列化, 那么究竟序列化的目的是什么? 其實序列化最終的目的是為了對象可以 跨平臺存儲,和進行網(wǎng)絡(luò)傳輸 。而我們進行跨平臺存儲和網(wǎng)絡(luò)傳輸?shù)姆绞骄褪荌O,而我們的IO支持的數(shù)據(jù)格式就是

    2024年02月08日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包