【Linux】应用层协议序列化和反序列化

这篇具有很好参考价值的文章主要介绍了【Linux】应用层协议序列化和反序列化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【Linux】应用层协议序列化和反序列化,Linux,linux,socket,序列化和反序列化

欢迎来到Cefler的博客😁
🕌博客主页:折纸花满衣
🏠个人专栏:题目解析
🌎推荐文章:C++【智能指针】

【Linux】应用层协议序列化和反序列化,Linux,linux,socket,序列化和反序列化


前言
在正式代码开始前,会有一些前提知识引入


👉🏻序列化和反序列化

在网络应用层中,序列化(Serialization)和反序列化(Deserialization)是将数据转换为可在网络上传输的格式,并从网络接收的数据恢复为本地数据结构的过程。

🌈序列化(Serialization):

序列化是将数据对象转换为一系列字节的过程,以便在网络上传输或存储到磁盘上。序列化的目标是创建一个可以被发送到其他系统或进程,并且能够被正确解释和还原的数据表示形式。在网络应用中,常见的序列化格式包括JSON(JavaScript Object Notation)、XML(eXtensible Markup Language)、Protocol Buffers、MessagePack等。

序列化的过程通常涉及以下步骤:

  1. 选择序列化格式:根据数据的特性和需求选择合适的序列化格式。
  2. 定义数据结构:确定要序列化的数据对象的结构,并为其定义序列化规则。
  3. 将数据转换为字节流:根据所选的序列化格式,将数据对象转换为字节流。
  4. 传输或存储:将序列化后的字节流发送到网络或者存储到磁盘上。

🌈反序列化(Deserialization):

反序列化是将序列化后的数据流转换回原始数据对象的过程。在接收到网络传输的数据后,需要对其进行反序列化以还原成原始数据对象。

反序列化的过程通常包括以下步骤:

  1. 接收数据流:从网络或者磁盘读取序列化后的数据流。
  2. 解析数据:根据所选的序列化格式,解析字节流并将其转换为数据对象。
  3. 数据还原:根据序列化规则和数据结构,将解析后的数据转换为原始数据对象。
  4. 应用数据:将还原后的数据对象用于应用程序的后续处理。

序列化和反序列化在网络通信中扮演着重要的角色,它们允许不同系统之间以统一的方式进行数据交换,同时也提供了数据传输的可靠性和可扩展性。


📒 一个小故事理解序列化和反序列化

故事标题:糖果工厂的序列化奇遇

一天,糖果工厂的老板决定向全球各地拓展市场,他决定使用一种特殊的糖果序列化器来包装他的糖果,以确保它们在长途运输中保持新鲜和美味。

序列化器(Serializationizer)是一台神奇的机器,它可以将任何形状、口味的糖果转换成一种特殊的串口糖果,这种串口糖果可以轻松地传输到世界各地,并在需要时还原为原始的糖果。

老板向工厂的工程师们解释了他的计划,然后开始了序列化器的操作。首先,他们把一袋五彩斑斓的糖果放进了序列化器中,它发出了一声“嘟噜嘟噜”的声音,然后从另一端输出了一串光滑而有序的串口糖果。

工程师们快乐地向老板展示他们的成果,老板也很满意。于是,他们将这些串口糖果装进了特殊的包装盒,准备发往全球各地的客户。

然而,一名新来的工程师在整理文件时不小心碰到了序列化器的控制台,他误触了一个按钮,导致序列化器的设置发生了改变。

于是,下一个批次的糖果被转换成了一种奇怪的形状,颜色也变得混乱不堪。这些串口糖果被送到了全球各地,但客户们收到后都表示了不满,称他们从未见过如此奇特的糖果。

老板赶紧调查了原因,发现了新工程师的失误。他们及时纠正了序列化器的设置,重新开始了正常的生产。这次,他们确保了每个糖果被正确序列化,而不是变成了像乱七八糟的串口糖果。

结局: 糖果工厂重新获得了客户的信任,全球各地的人们再次享用到了美味的糖果。而那位新工程师也从这个经历中学到了重要的教训:在操作序列化器时一定要小心,否则可能会引发一场糖果灾难!

【Linux】应用层协议序列化和反序列化,Linux,linux,socket,序列化和反序列化

👉🏻三次握手和四次挥手

当建立和终止TCP连接时,通常会执行三次握手(Three-Way Handshake)和四次挥手(Four-Way Handshake)的过程,以确保通信的可靠性和正确性。

🌈三次握手(Three-Way Handshake):

  1. 客户端发送同步序列号(SYN)报文:

    • 客户端首先向服务器发送一个带有SYN标志的报文,表示客户端请求建立连接,并选择一个初始的序列号(Sequence Number)。
  2. 服务器确认连接请求:

    • 服务器收到客户端的SYN报文后,会发送一个带有SYN和ACK标志的报文,表示同意建立连接,并确认收到了客户端的连接请求,并选择自己的初始序列号。
  3. 客户端确认连接:

    • 客户端收到服务器的SYN+ACK报文后,会发送一个带有ACK标志的报文给服务器,表示确认连接建立。

这样,客户端和服务器之间的TCP连接就建立起来了,可以开始进行数据传输。

🌈 四次挥手(Four-Way Handshake):

  1. 客户端发送关闭连接请求:

    • 客户端发送一个带有FIN(结束)标志的报文给服务器,表示客户端不再发送数据,但仍愿意接收数据。
  2. 服务器确认关闭请求并关闭数据传输:

    • 服务器收到客户端的FIN报文后,会发送一个带有ACK标志的报文给客户端,表示确认关闭请求,并停止向客户端发送数据,但仍可以接收数据。
  3. 服务器发送关闭连接请求:

    • 服务器发送一个带有FIN标志的报文给客户端,表示服务器也准备关闭连接。
  4. 客户端确认关闭请求并关闭连接:

    • 客户端收到服务器的FIN报文后,会发送一个带有ACK标志的报文给服务器,表示确认关闭请求,并关闭连接。

这样,客户端和服务器之间的TCP连接就完全关闭了。四次挥手的过程中,双方都可以发送数据,并且在关闭连接后都不能再发送数据。


📒 一个小例子理解三次握手和四次挥手
好的,让我们用一种有趣的方式来理解三次握手和四次挥手。

🫱🏻🫲🏻 三次握手(Three-Way Handshake):

想象一下你和朋友约好去吃披萨。这里有个名叫小明的朋友(客户端)和一个叫披萨店的地方(服务器)。

  1. 小明: “嗨,披萨店老板!我想要一份披萨!”(发送SYN)

  2. 披萨店老板: “好的,小明,你想要什么口味的披萨?”(发送SYN+ACK)

  3. 小明: “我想要意大利香肠披萨!”(发送ACK)

现在,小明和披萨店之间建立了连接,披萨店知道了小明的口味,准备开始制作披萨。

🤲🏻 四次挥手(Four-Way Handshake):

披萨终于做好了,大家都吃得很开心,然后就是结束这次美好的披萨时光。

  1. 小明: “披萨店老板,谢谢你的披萨,我不想再点了!”(发送FIN)

  2. 披萨店老板: “不客气,小明,欢迎下次再来!披萨店休息了!”(发送ACK)

  3. 披萨店老板: “好了,披萨店打烊了,我们关门了!”(发送FIN)

  4. 小明: “明白了,披萨店老板,再见!”(发送ACK)

这样,小明和披萨店之间的交流就结束了,披萨店可以关门休息了,而小明也满足地离开了。
【Linux】应用层协议序列化和反序列化,Linux,linux,socket,序列化和反序列化

👉🏻一些概念知识

全双工

全双工(Full Duplex)是指数据通信系统中能够同时实现双向通信的能力,即在同一时间点上可以同时进行发送和接收数据的操作。这种模式下,通信双方能够同时进行双向数据传输,而不需要等待对方完成发送或接收操作。

在全双工通信中,发送和接收数据的通道是完全独立的,彼此之间互不干扰。这意味着通信双方可以在不同的频率或者不同的频道上同时进行通信,而不会造成碰撞或数据丢失。

全双工通信通常用于需要高速、实时双向数据传输的场景,比如电话通话、视频会议、网络通信等。相比于半双工通信(Half Duplex),全双工通信具有更高的通信效率和更低的延迟,因为它允许发送和接收数据同时进行,而不需要等待切换操作。

在网络通信中,全双工模式通常通过使用不同的通信频率(如Wi-Fi、蓝牙等无线通信)、不同的通信信道(如以太网的双绞线)或者使用不同的时隙(如时分多址技术)来实现。这种模式在现代通信技术中被广泛应用,为用户提供了更流畅、更高效的通信体验。

TCP和UDP对比

TCP(传输控制协议)和UDP(用户数据报协议)是两种常用的网络传输协议,它们在数据传输时有着不同的特点和适用场景:

  1. 连接性:

    • TCP是面向连接的协议,它在通信双方建立连接后才能进行数据传输,确保数据的可靠性和顺序性。
    • UDP是无连接的协议,通信双方无需建立连接即可直接发送数据,因此不保证数据的可靠性和顺序性。
  2. 可靠性:

    • TCP提供可靠的数据传输,通过序号、确认和重传机制来确保数据的完整性和可靠性,保证数据不会丢失或损坏。
    • UDP不提供可靠性保证,数据包可能会丢失、重复或者乱序,因此在一些实时性要求高、但对数据完整性要求较低的场景下使用较多。
  3. 流量控制(面向字节流)和拥塞控制:

    • TCP通过流量控制和拥塞控制机制来调节数据传输速率,以避免网络拥塞和数据丢失。
    • UDP不提供流量控制和拥塞控制,数据传输速率由发送方直接决定,可能会导致网络拥塞。
  4. 适用场景:

    • TCP适用于需要可靠数据传输和顺序传输的场景,如文件传输、网页浏览、电子邮件等。
    • UDP适用于实时性要求高、但对数据完整性要求较低的场景,如音频和视频流、在线游戏、实时通信等。
  5. 开销:

    • TCP的头部开销较大,包含了序号、确认、窗口大小等信息,因此在传输小量数据时可能会存在较大的开销。
    • UDP的头部开销较小,只包含了源端口、目标端口、长度和校验和等基本信息,因此在传输小量数据时开销较小。

总的来说,TCP提供了可靠的数据传输和顺序传输,适用于对数据完整性要求高的场景;而UDP提供了更快速的数据传输和更低的开销,适用于实时性要求高、但对数据完整性要求较低的场景。选择使用哪种协议取决于具体的应用需求和性能要求。

send和recv

当编写网络程序时,常用的函数之一是sendrecv,它们通常用于在TCP连接上发送和接收数据。

🍓send 函数:

  • 功能: 用于在已建立的连接上发送数据。
  • 语法: send(socket, data, flags)
    • socket:指定发送数据的套接字。
    • data:要发送的数据。
    • flags:指定发送操作的可选标志。

🍓recv 函数:

  • 功能: 用于从已建立的连接上接收数据。
  • 语法: recv(socket, buffersize, flags)
    • socket:指定接收数据的套接字。
    • buffersize:指定接收缓冲区的大小。
    • flags:指定接收操作的可选标志。

这两个函数在TCP编程中非常常见,它们允许程序在客户端和服务器之间进行双向通信。

🍴 与sendto 函数和 recvfrom 函数的区别:

  • sendto 函数: 用于在无连接的套接字上发送数据。通常用于UDP套接字。
    • 它需要指定目标地址和端口。
  • recvfrom 函数: 用于从无连接的套接字上接收数据。通常用于UDP套接字。
    • 它返回发送数据的源地址和端口。

在网络编程中,write和read函数通常用于TCP套接字,因此它们也是基于已连接的。

总的来说,sendrecv函数适用于TCP连接,而sendtorecvfrom函数适用于UDP套接字。前者是基于连接的,后者是无连接的。

👉🏻TCP通信-使用相同结构化字段传输数据(但未真正的序列化和反序列化)

代码目录:
【Linux】应用层协议序列化和反序列化,Linux,linux,socket,序列化和反序列化

Protocol.hpp(协议内容)

#pragma once

#include<iostream>
#include<memory>
using namespace std;

class Request
{
public:
    Request()
    {}
    Request(int x,int y,char op)
    :_data_x(x),_data_y(y),_oper(op)
    {}


    void Inc()
    {
        _data_x++;
        _data_y++;
    }
    void Debug()
    {
        cout<<"_data_x: "<<_data_x<<endl;
        cout<<"_data_y: "<<_data_y<<endl;
        cout<<"_oper: "<<_oper<<endl;
    }


private:
    int _data_x;
    int _data_y;
    char _oper;//操作数
};

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

    }
private:
    int _result;
    int _code;
};

//工厂模式,建造类设计模式,直接返回指针对象
class Factory
{
public:
    shared_ptr<Request> BuildRequest()
    {
        shared_ptr<Request> req = make_shared<Request>();
        return req;
    }
    
       shared_ptr<Request> BuildRequest(int x,int y,char op)
       {
        shared_ptr<Request> req = make_shared<Request>(x,y,op);
        return req;
    }

    shared_ptr<Response> BuildResponse()
    {
        shared_ptr<Response> resp = make_shared<Response>();

        return resp;
    }
      shared_ptr<Response> BuildResponse(int result,int code)
    {
        shared_ptr<Response> resp = make_shared<Response>(result,code);

        return resp;
    }

};

Socket.hpp(封装socket通信的功能)

#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>

#define Convert(addrptr) ((struct sockaddr*)addrptr)

using namespace std;

namespace Net_Work
{
    const static int defaultsockfd = -1;
    const int backlog = 5;
    enum
    {
        SocketError = 1,
        BindError,
        ListenError,
    };
    //封装一个基类:Socket接口类
    class Socket
    {
    public:
        virtual ~Socket(){}
        virtual void CreateSocketOrDie() = 0;//创建一个套接字
        virtual void BindSocketOrDie(uint16_t port) = 0;//套接字进行绑定网络信息
        virtual void ListenSocketOrDie(int backlog) = 0;//进行监听
        virtual Socket* AcceptConnection(string * peerip,uint16_t* peerport)=0;//接收连接,并返回一个新的套接字
        virtual bool ConnectServer(string& peerip,uint16_t peerport)=0;//连接服务端
        virtual int GetSockFd() = 0;//返回套接字描述符
        virtual void SetSockFd(int sockfd) = 0;//
        virtual void CloseSocket() = 0;//关闭套接字
    public:
        void BuildListenSocketMethod(uint16_t port,int backlog)//创建一个监听服务
        {
            //1.创建套接字
            CreateSocketOrDie();
            //2.套接字进行绑定网络信息
            BindSocketOrDie(port);
            //3.开始监听
            ListenSocketOrDie(backlog);
        }
        bool BuildConnectSocketMethod(string& serverip,uint16_t& serverport)//创建一个连接服务
        {
            //1.创建套接字
            CreateSocketOrDie();
            return ConnectServer(serverip,serverport);

        }
        void BuildNormalSocketMethod(int sockfd)
        {
            SetSockFd(sockfd);
        }
    };

    //实现Tcp套接字
    class TcpSocket:public Socket
    {
    public:
        TcpSocket(int sockfd = defaultsockfd )
        :_sockfd(sockfd)
        {

        }
        ~TcpSocket(){}
        /
       
         void CreateSocketOrDie() override//创建一个套接字
         {
            _sockfd = socket(AF_INET,SOCK_STREAM,0);
            if(_sockfd<0)
                exit(SocketError);
         }

         void BindSocketOrDie(uint16_t port) override//套接字进行绑定网络信息
         {
            //本地网络信息初始化
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));
            local.sin_family = AF_INET;
            local.sin_addr.s_addr = INADDR_ANY;//服务端的ip由本地随机绑定
            local.sin_port = htons(port);

            //开始绑定
            int n = bind(_sockfd,Convert(&local),sizeof(local));
            if(n<0) exit(BindError);
         }
         void ListenSocketOrDie(int backlog) override//进行监听
         {
            int n = listen(_sockfd,backlog);
            if(n<0) exit(ListenError);
         }
        Socket* AcceptConnection(string * peerip,uint16_t* peerport)override//接收连接
        {
            struct sockaddr_in peer;//用来存储客户端的地址信息
            socklen_t len = sizeof(peer);
            int newsockfd = accept(_sockfd,Convert(&peer),&len);
            if(newsockfd<0)
                return nullptr;

            *peerport = ntohs(peer.sin_port);//网络序列本地化
            *peerip = inet_ntoa(peer.sin_addr);

            Socket* s = new TcpSocket(newsockfd);
            return s;
        }
         bool ConnectServer(string& serverip,uint16_t serverport)override//连接服务端
         {
            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());//ip网络字节序化,4字节

            int n = connect(_sockfd,Convert(&server),sizeof(server));
            if(n==0)
                return true;
            else
                return false;
         }
         int GetSockFd() override//返回套接字描述符
         {
            return _sockfd;
         }
         void SetSockFd(int sockfd) override//
         {
            _sockfd = sockfd;
         }
         void CloseSocket() override//关闭套接字
         {
            if(_sockfd>defaultsockfd)
                close(_sockfd);
         }
    private:
        int _sockfd;
    };
};

TcpServer.hpp(封装服务端功能)

#pragma once

#include"Socket.hpp"
#include<pthread.h>
#include<functional>

using func_t = function<void(Net_Work::Socket* sockp)>;

class TcpServer;

class ThreadData
{
public:
    ThreadData(TcpServer* tcp_this,Net_Work::Socket* sockp)
    :_this(tcp_this),_sockp(sockp)
    {}
public:
    TcpServer* _this;//TcpServer的指针对象
    Net_Work::Socket* _sockp;//套接字指针对象
};


class TcpServer
{
public:
    TcpServer(uint16_t port,func_t handler_request)
    :_port(port),_listensocket(new Net_Work::TcpSocket()),_hanlder_request(handler_request)
    {
        _listensocket->BuildListenSocketMethod(_port,Net_Work::backlog);//开启监听事务
    }
    static void * ThreadRun(void* args)//因为pthread_create要求方法参数中的参数必须只有一个void*
    //所以必须变为静态,否则成员函数第一个参数默认隐式为this指针
    {
        //因为执行的是多线程,这里我们也没有封装线程的自动回收
        //所以为了不发生线程阻塞,我们要让当前线程与主线程分离,不影响主线程,并且自己做完任务自己回收
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);
       
        td->_this->_hanlder_request(td->_sockp);//执行_hanlder_request方法

        td->_sockp->CloseSocket();//关闭accept的新套接字
        delete td->_sockp;//销毁指针
        delete td;
        return nullptr;
    }
    void Loop()
    {
         while(true)
        {
            string peerip;
             uint16_t peerport;
            Net_Work::Socket* newsocket = _listensocket->AcceptConnection(&peerip,&peerport);//接收客户端信息
            if(newsocket==nullptr) continue;
                 cout<<"获取一个新连接,sockfd:"<<newsocket->GetSockFd()<<"client info: "<<peerip<<" "<<peerport<<endl;

            //用完后关闭newsocket
            //newsocket->CloseSocket();   

            //使用多线程进行处理任务
            pthread_t tid;
            ThreadData* td = new ThreadData(this,newsocket);
            pthread_create(&tid,nullptr,ThreadRun,td);//线程创建并执行相对应任务
         }
    }

    ~TcpServer()
    {
        delete _listensocket;
    }

private:
    uint16_t _port;
    Net_Work::Socket* _listensocket;

public:
    func_t _hanlder_request;//request执行方法

};

TcpServerMain.cc

#include"Protocol.hpp"
#include"Socket.hpp"
#include"TcpServer.hpp"
#include<memory>

using namespace Net_Work;
void HandlerRequest(Socket* sockp)
{
    while(true)
    {
        struct Request req;//用来存储客户端发来的需求信息
        recv(sockp->GetSockFd(),&req,sizeof(req),0);//接收
        req.Debug();//打印信息
    }
}

int main(int argc,char* argv[])
{
     if(argc != 2)
    {
        cout << "Usage : " << argv[0] << " port" << std::endl;
        return 0;
    }
    uint16_t  localport = stoi(argv[1]);

    unique_ptr<TcpServer> svr (new TcpServer(localport,HandlerRequest));//unique_ptr只能支持移动构造

    svr->Loop();//server开始不断获取新连接
    return 0;
}

TcpClientMain.cc

#include"Protocol.hpp"
#include"Socket.hpp"


int main(int argc,char* argv[])
{
    if(argc != 3)
    {
        cout << "Usage : " << argv[0] << " serverip serverport" << std::endl;
        return 0;
    }
    string serverip = argv[1];
    uint16_t  serverport = stoi(argv[2]);

    Net_Work::Socket* s = new Net_Work::TcpSocket();
    if(!s->BuildConnectSocketMethod(serverip, serverport))
    {
        cerr << "connect " << serverip << ":" << serverport << " failed" << std::endl;
    }
    cout << "connect " << serverip << ":" << serverport << " success" << std::endl;

    unique_ptr<Factory> factory = make_unique<Factory>();//创建一个工厂对象指针(后续可以生产需求和回应),工厂只能有一个,所以用unique_ptr指针

    shared_ptr<Request> req = factory->BuildRequest(10,20,'+');

    while(true)
    {
        req->Inc();
        send(s->GetSockFd(),&(*req),sizeof(*req),0);//将需求信息发送给服务端
        sleep(1);
    }

    s->CloseSocket();//关闭套接字
    return 0;
}

实现效果

【Linux】应用层协议序列化和反序列化,Linux,linux,socket,序列化和反序列化


如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长
【Linux】应用层协议序列化和反序列化,Linux,linux,socket,序列化和反序列化

【Linux】应用层协议序列化和反序列化,Linux,linux,socket,序列化和反序列化文章来源地址https://www.toymoban.com/news/detail-856606.html

到了这里,关于【Linux】应用层协议序列化和反序列化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】应用层之HTTP协议

    在应用层,需要我们传递应用层所需特殊的数据格式,这种数据可能是连续数据,例如int类型的整形变量,也可能是string类型的字符串,也可能是多个变量构成的结构体,那么就意味着我们发送的数据可能是连续的,也可能是不连续的,这时为了统一数据的解析方法,我们对

    2024年02月12日
    浏览(44)
  • [linux--->应用层网络通信协议]

    协议本质是收发端双方约定好格式的数据,常见协议是用结构体或者类的方式来表达,结构化的数据是为了方便被应用层解读,这个结构体中可能包括发送者ip和端口号以及主机名,还有通信信息,应用层可以用结构体区分并使用信息;使用结构体直接传递,但是可能会因为系统的不同

    2024年02月15日
    浏览(38)
  • Linux网络:应用层之HTTP协议

    我们程序员写的一个个解决实际问题,满足日常需求的网络程序,都是在应用层。 协议是一种约定。网络协议是计算机网络中通信双方都必须遵守的一组约定。 在网络通信中,都是以 “字符串” 的方式来发送和接收数据的。 如果要发送和接收一些结构化的数据,就需要序

    2023年04月26日
    浏览(53)
  • 【Linux后端服务器开发】协议定制(序列化与反序列化)

    目录 一、应用层协议概述 二、序列化与反序列化 Protocal.h头文件 Server.h头文件 Client.h头文件 server.cpp源文件 client.cpp源文件 什么是应用层 ?我们通过编写程序解决一个个实际问题、满足我们日常需求的网络程序,都是应用层程序。 协议是一种“约定”,socket的api接口,在读

    2024年02月16日
    浏览(40)
  • 【Linux】应用层协议:HTTP和HTTPS

    每个人都可以很喜欢每个人,但喜欢治不了病,喜欢买不了东西,喜欢不能当饭吃,喜欢很廉价… 1.1 URL的组成 1. 在之前的文章中我们实现了一个网络版本的计算器,在那个计算器中揉合了协议定制以及序列化反序列化的内容,我们当时也自己定制了一套协议标准,比如请求

    2024年02月10日
    浏览(49)
  • 【Linux】TCP网络套接字编程+协议定制+序列化和反序列化

    悟已往之不谏,知来者之可追。抓不住的就放手,属于你的都在路上…… 1. 为了让我们的代码更规范化,所以搞出了日志等级分类,常见的日志输出等级有DEBUG NORMAL WARNING ERROR FATAL等,再配合上程序运行的时间,输出的内容等,公司中就是使用日志分类的方式来记录程序的输

    2024年02月08日
    浏览(69)
  • 【Linux】简单的网络计算器的实现(自定义协议,序列化,反序列化)

    我们需要实现一个服务器版的加法器. 我们需要客户端把要计算的两个加数发过去, 然后由服务器进行计算, 最后再把结果返回给客户端` 详细可参考我之前写的博客【Linux】记录错误信息日志的实现

    2024年02月19日
    浏览(55)
  • 【Linux网络】网络应用层的 http 和 https协议

    在之前学习序列化和反序列化的时候,认识到主机之间传输结构数据的时候,最好是通过某种约定将结构数据序列化成一串字符串,接收方再通过反序列化将字符串转换成结构数据。以上说的这种约定,其实可以看成是用户层通信的一种协议,是由程序猿自己定的。   实际

    2024年02月02日
    浏览(63)
  • 【网络】协议定制+序列化/反序列化

    如果光看定义很难理解序列化的意义,那么我们可以从另一个角度来推导出什么是序列化, 那么究竟序列化的目的是什么? 其实序列化最终的目的是为了对象可以 跨平台存储,和进行网络传输 。而我们进行跨平台存储和网络传输的方式就是IO,而我们的IO支持的数据格式就是

    2024年02月08日
    浏览(42)
  • 协议,序列化,反序列化,Json

    协议究竟是什么呢?首先得知道主机之间的网络通信交互的是什么数据,像平时使用聊天APP聊天可以清楚,用户看到的不仅仅是聊天的文字,还能够看到用户的头像昵称等其他属性。也就可以证明网络通信不仅仅是交互字符串那么简单。事实上网络通信还可能会通过一个结构

    2024年02月13日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包