Linux--序列化与反序列化

news2024/9/19 10:48:55

序列化

序列化是指将数据结构或对象状态转换成可以存储或传输的格式的过程。在序列化过程中,对象的状态信息被转换为可以保持或传输的格式(如二进制、XML、JSON等)。序列化后的数据可以被写入到文件、数据库、内存缓冲区中,或者通过网络发送到另一个系统。

序列化的主要目的包括:

  • 持久化:将对象状态保存到存储系统中,以便程序在重新启动时能够重新加载这些数据。
  • 网络传输:在分布式系统中,对象需要通过网络发送到其他节点,序列化是实现这一点的关键步骤。
  • 数据交换:不同的应用程序或系统之间可能需要交换数据,序列化提供了一种标准化的数据格式。

反序列化

反序列化是序列化的逆过程,即将序列化后的数据(如二进制、XML、JSON等)恢复成原始的数据结构或对象状态。在反序列化过程中,原始的数据格式被解析并重新构建成原始对象或数据结构。

反序列化的主要目的是:

  • 恢复对象状态:从存储系统或网络接收的数据中恢复对象的状态。
  • 数据使用:在应用程序中使用反序列化后的数据。

JSON

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript的一个子集,但是JSON是独立于语言的,许多编程语言都有解析JSON的库,因此JSON成为了现代互联网中数据交换的标准格式之一。

Jsoncpp

Jsoncpp是一个开源的C++库,主要用于解析和生成JSON数据格式。

安装方式:
在这里插入图片描述

特点:

  • 轻量级:Jsoncpp具有很小的代码体积和低的内存占用,非常适合嵌入式系统或资源受限的环境。
  • 跨平台:Jsoncpp可以在多种操作系统上运行,包括Windows、Linux、Mac等。
  • 简单易用:Jsoncpp提供了简洁的API,使得解析和生成JSON数据变得非常容易。开发人员可以通过简单的函数调用来实现JSON数据的读取、修改和生成。
  • 高性能:Jsoncpp采用了高效的算法和数据结构,提供了快速的JSON解析和生成功能。
  • 可靠稳定:Jsoncpp经过广泛的测试和使用,已经成为一个成熟的库,具有良好的稳定性和可靠性。

核心功能:

Jsoncpp的核心数据结构是Json::Value类,它表示JSON数据的各种类型,包括对象、数组、字符串、数字等。通过Json::Value类及其相关方法,开发者可以直观地操作JSON数据,无需关注复杂的内部实现细节。

Jsoncpp还提供了几个重要的类来支持JSON数据的解析和生成,包括:

Json::Reader:用于将JSON字符串或文件解析成Json::Value对象。
Json::Writer:(及其子类如Json::FastWriter、Json::StyledWriter等):用于将Json::Value对象序列化为JSON字符串。

在这里插入图片描述

示例:网络计算器

实现一个服务器版的计算器,客户端将要要计算的两个数发送到服务端,服务端计算好将结果返回给客户端;

期间,我们会用一种结构体存储对应的计算的两个数以及符号;数据通过序列化发送到服务端,服务端需要将字符串反序列化解析得到数据;

Socket.hpp

#include <iostream>
#include <string>
#include <functional>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
#include <sys/types.h>
#include <memory>
#include "InetAddr.hpp"
#include "Log.hpp"

namespace socket_ns
{
    class Socket;
    const static int gbacklog=8;//默认最大连接数
    using socket_sptr=std::shared_ptr<Socket>;//套接字指针

    enum
    {
        SOCKET_ERROR = 1,
        BIND_ERROR,
        LISTEN_ERROR,
        USAGE_ERROR
    };

    //在基类创建一系列虚函数,只要派生类能用到就在这里创建
    class Socket
    {
    public:
        virtual void CreateSocketOrDie() =0; //创建套接字
        virtual void BindSocketOrDie(InetAddr& addr) =0;  //绑定套接字
        virtual void ListenSocketOrDie()=0; //监听套接字
        virtual socket_sptr Accepter(InetAddr* addr) =0; //接受客户端
        virtual bool Connector(InetAddr &addr) = 0; //连接客户端
        virtual int SockFd() = 0; //获取Sockfd
        virtual int Recv(std::string *out) = 0; //接收对方信息
        virtual int Send(const std::string &in) = 0; //发送给对方信息

    public:
        //创建监听套接字,将一系列操作细分化,直接引用对应函数直接创建
        void BuildListenSocket(InetAddr& addr)
        {
            CreateSocketOrDie();
            BindSocketOrDie(addr);
            ListenSocketOrDie();
        }
        bool BuildClientSocket(InetAddr &addr)
        {
            CreateSocketOrDie();
            return Connector(addr);
        }
    };

    class TcpSocket : public Socket
    {
    public:
        TcpSocket(int sockfd=-1)
        :_sockfd(sockfd)
        {}
        void CreateSocketOrDie() override  //override明确的重写基类函数
        {
            _sockfd=socket(AF_INET,SOCK_STREAM,0);
            if(_sockfd<0)
            {
                LOG(FATAL, "socket error");
                exit(SOCKET_ERROR);
            }
            LOG(DEBUG, "socket create success, sockfd is : %d\n", _sockfd);
        }
        void BindSocketOrDie(InetAddr& addr) override
        {
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(addr.Port());
            local.sin_addr.s_addr = inet_addr(addr.Ip().c_str());

            int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
            if (n < 0)
            {
                LOG(FATAL, "bind error");
                exit(BIND_ERROR);
            }
            LOG(DEBUG, "bind success, sockfd is : %d\n", _sockfd);
        }
        void ListenSocketOrDie() override
        {
            int n=listen(_sockfd,gbacklog);
            if (n < 0)
            {
                LOG(FATAL, "listen error");
                exit(LISTEN_ERROR);
            }
            LOG(DEBUG, "listen success, sockfd is : %d\n", _sockfd);
        }
        socket_sptr Accepter(InetAddr* addr) override
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            int sockfd = accept(_sockfd,(struct sockaddr*)&peer,&len);
            if (sockfd < 0)
            {
                LOG(WARNING, "accept error\n");
                return nullptr;
            }
            *addr=peer;
            socket_sptr sock=std::make_shared<TcpSocket>(sockfd);
            return sock;
        }
        virtual bool Connector(InetAddr& addr)
        {
            struct sockaddr_in server;
            memset(&server,0,sizeof(server));
            server.sin_family=AF_INET;
            server.sin_addr.s_addr=inet_addr(addr.Ip().c_str());
            server.sin_port=htons(addr.Port());

            int n=connect(_sockfd,(struct sockaddr*)&server,sizeof(server));
            if (n < 0)
            {
                std::cerr << "connect error" << std::endl;
                return false;
            }
            return true;
        }
        int Recv(std::string *out) override
        {
            char inbuffer[1024];
            ssize_t n = recv(_sockfd,inbuffer,sizeof(inbuffer)-1,0);
            if (n > 0)
            {
                inbuffer[n] = 0;
                *out += inbuffer; // 接收次数可能不只一次,一般是多次的,
                
            }
            return n;
        }
        int Send(const std::string &in) override
        {
            int n = send(_sockfd,in.c_str(),in.size(),0);
            return n;
        }
        int SockFd() override
        {
            return _sockfd;
        }
        ~TcpSocket()
        {}
    private:
        int _sockfd;
    };
}


在这里插入图片描述

ProToCol.hpp

主要是发出请求时将数据序列化和接收数据时反序列化;服务端响应时接收数据的反序列化和发送结果时序列化;

#pragma once 
#include <iostream>
#include <string>
#include<unistd.h>
#include<memory>
#include<jsoncpp/json/json.h>

namespace protocol_ns
{
    // 协议的样子:
    // 报文 = 报头+有效载荷
    // "有效载荷的长度"\r\n"有效载荷"\r\n
    const std::string SEP= "\r\n";

    // 解决TCP的粘报问题,TCP 读取不全的问题
    std::string Encode(const std::string &json_str)
    {
        int json_str_len = json_str.size(); //有效载荷的长度
        std::string proto_str = std::to_string(json_str_len); //转为string
        proto_str += SEP; //+ 分隔符
        proto_str += json_str;// + 数据字符串
        proto_str += SEP;// + 分隔符
        return proto_str; //返回一个报文
    }

    //将报文分析出数据字符串出来
    std::string Decode(std::string &inbuffer)
    {
        auto pos = inbuffer.find(SEP); //找到分隔符的位置
        if (pos == std::string::npos)
            return std::string();
        
        std::string len_str = inbuffer.substr(0, pos);//前头的有效数据长度的字符串
        if (len_str.empty())
            return std::string();
        int packlen = std::stoi(len_str);//记录数据字符串的实际长度(传递时的差错主要出在这里)

        int total = packlen + len_str.size() + 2 * SEP.size(); //报文总长度
        if (inbuffer.size() < total)
            return std::string();
        
        std::string package = inbuffer.substr(pos + SEP.size(), packlen); //取出数据字符串
        inbuffer.erase(0, total); //删除掉原先的报文
        return package;
    }
    //请求将我们的数据序列化和反序列化(客户端)    
    class Request
    {
    public:
        Request()
        {
        }
        Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper)
        {
        }   
        //序列化:将结构体数据转换为字符串
        bool Serialize(std::string* out)
        {
            Json::Value root; //Json::Value: Json格式的值
            root["x"] = _x;
            root["y"] = _y;
            root["oper"] = _oper;

            Json::FastWriter writer;
            *out=writer.write(root); //将Json值转换为字符串
            return true;
        }
        
        //反序列化:将字符串转换为结构体数据
        bool DeSerialize(const std::string& in)
        {
            Json::Value root;
            Json::Reader reader;//解析字符串
            bool res=reader.parse(in,root);//将字符串转为Json值,存放于root中
            if (!res)
                return false;

            //再将Json值转为结构体数据
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
            return true;
            
        }
    public:
        int _x;
        int _y;
        char _oper; //操作符 _x 加减乘除 _y
    };

    //将结果序列化和反序列化(服务端)
    class Response
    {
    public:
        Response()
        {
        }
        Response(int result, int code) : _result(result), _code(code)
        {
        }
        bool Serialize(std::string *out)
        {
            // 转换成为字符串
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;

            Json::FastWriter writer;
            // Json::StyledWriter writer;
            *out = writer.write(root);
            return true;
        }
        bool Deserialize(const std::string &in)
        {
            Json::Value root;
            Json::Reader reader;
            bool res = reader.parse(in, root);
            if (!res)
                return false;

            _result = root["result"].asInt();
            _code = root["code"].asInt();
            return true;
        }
    public:
        int _result; // 结果
        int _code;   // 0:success 1: 除0 2: 非法操作 3. 4. 5
    };

    //创建需求
    class Factory
    {
    public:
      
        Factory()
        {
            srand(time(nullptr) ^ getpid());
            opers = "+-*/%^&|";                                                                                                                 
        }

        std::shared_ptr<Request> BuildRequest()
        {
            int x = rand() % 10 + 1;
            usleep(x * 10);
            int y = rand() % 5; // [0,1,2,3,4]
            usleep(y * x * 5);
            char oper = opers[rand() % opers.size()];
            std::shared_ptr<Request> req= std::make_shared<Request>(x,y,oper);
            return req;
        }
        std::shared_ptr<Response> BuildResponse()
        {
            return std::make_shared<Response>();
        }
        ~Factory()
        {
        }
        
    private:
        std::string opers;
    };
}

在这里插入图片描述

CalCulate.hpp

将已经反序列化的数据通过计算得出结果:

#pragma once
#include <iostream>
#include "ProToCol.hpp"

using namespace protocol_ns;

class Calculate
{
public:
    Calculate()
    {
    }

    //根据输入的请求通过实际计算转换为结果
    Response Excute(const Request &req)
    {
        Response resp(0, 0);

        switch (req._oper)
        {
        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._code = 1;
            }
            else
            {
                resp._result = req._x / req._y;
            }
        }
        break;
        case '%':
        {
            if (req._y == 0)
            {
                resp._code = 2;
            }
            else
            {
                resp._result = req._x % req._y;
            }
        }
        break;
        default:
            resp._code = 3;
            break;
        }
        return resp;
    }

     ~Calculate()
    {
    }

private:
};

在这里插入图片描述

TcpServerMain.cc

#include <iostream>
#include <functional>
#include <memory>
#include "TcpServer.hpp"
#include "ProToCol.hpp"
#include"CalCulate.hpp"
using namespace protocol_ns;

using callback_t = std::function<Response(const Request&)>;//响应计算结果的函数指针
void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " local_port\n"
              << std::endl;
}

//由于接收的是报文,需要通过反序列化和序列化反复转换并且期间要完成计算的服务
class Service
{
public:
    Service(callback_t cb) : _cb(cb)
    {
    }

    //套接字指针:客户端的sockfd   网络地址:客户端
    void ServiceHelper(socket_sptr sockptr,InetAddr client)
    {
        int sockfd = sockptr->SockFd();
        LOG(DEBUG, "get a new link, info %s:%d, fd : %d\n",client.Ip().c_str(),client.Port(),sockfd );
        std::string clientaddr = "[" + client.Ip() + ":" + std::to_string(client.Port()) + "] ";
        std::string inbuffer;

        while(true)
        {
            sleep(5);
            Request req;
            
            // 1.接收来自客户端的发送数据,接收时是已被序列化的数据信息
            int n = sockptr->Recv(&inbuffer); 
            if (n < 0)
            {
                LOG(DEBUG, "client %s quit\n", clientaddr.c_str());
                break;
            }

           
            std::string package;
            while (true)//传递途中可能会出现数据丢失,要通过循环直到找到有效正确的数据信息
            {
                //2.分析报文中的有效数据
                sleep(1);
                std::cout << "inbuffer: " << inbuffer << std::endl;
                package = Decode(inbuffer);//解析报文
                if (package.empty())
                    break;
                std::cout << "------------------------begin---------------" << std::endl;
                std::cout << "resq string:\n"<< package << std::endl;  

                // 3.反序列化,将字符串变为结构体信息
                req.DeSerialize(package);
                // 4. 业务处理
                Response resp = _cb(req);

                // 5. 对应答做序列化
                std::string send_str;
                resp.Serialize(&send_str);

                std::cout << "resp Serialize:" << std::endl;
                std::cout << send_str << std::endl; 

                // 6. 添加长度报头
                send_str = Encode(send_str);
                std::cout << "resp Encode:" << std::endl;
                std::cout << send_str << std::endl;

                // "len"\r\n"{             }"\r\n"
                sockptr->Send(send_str); // 本次不对发送做处理, EPOLL     
            }
        }
    }
private:
    callback_t _cb; //将需求转换为结果
};

// ./tcpserver port
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }
    uint16_t port = std::stoi(argv[1]);

    Calculate cal;
    Service calservice(std::bind(&Calculate::Excute, &cal, std::placeholders::_1));//通过Service解决报文问题
    io_service_t service = std::bind(&Service::ServiceHelper, &calservice, std::placeholders::_1, std::placeholders::_2);//将服务和服务器耦合
    std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(port, service);
    tsvr->Loop();
    return 0;
}

在这里插入图片描述

TcpClientMain.cc

#include <iostream>
#include <string>
#include <memory>
#include <ctime>
#include "Socket.hpp"
#include "ProToCol.hpp"
#include "InetAddr.hpp"

using namespace socket_ns;
using namespace protocol_ns;

void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " serverip serverport\n"<< std::endl;           
}

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

    std::string serverip = argv[1];//服务端ip
    uint16_t serverport = std::stoi(argv[2]);//服务端端口号
    InetAddr serveraddr(serverip, serverport);//创建网络地址
    Factory factory;//
    std::shared_ptr<Socket> cli=std::make_shared<TcpSocket>();//创建套接字的智能指针
    bool res=cli->BuildClientSocket(serveraddr); //创建Client套接字并连接到服务端
    std::string inbuffer; //接收应答时存储对方的数据
    while (res)
    {
        sleep(1);
        std::string str;
        //一次创建5个请求出来
        //for(int i=0;i<5;i++)
        //{
            // 1. 构建一个请求
            auto req = factory.BuildRequest();

            // 2. 对请求进行序列化
            std::string send_str; //序列化后保存于此
            req->Serialize(&send_str);

            std::cout << "Serialize: \n"<< send_str << std::endl;
                      
            // 3. 添加长度报头
            send_str = Encode(send_str);
            std::cout << "Encode: \n"<< send_str << std::endl;
                      
            str += send_str;
        //}
        //4.发送报文
        cli->Send(str);

        // 5. 读取应答
        int n = cli->Recv(&inbuffer);//接收应答
        if (n <= 0)
            break;
        std::string package = Decode(inbuffer); //解析报文
        if (package.empty()) //一旦为空那么继续解析下一个报文
            continue;

        // 6. 反序列化
        auto resp = factory.BuildResponse();
        resp->Deserialize(package);


        std::cout<<"result: "<<resp->_result<<"["<< resp->_code <<"]"<<std::endl;
    }
}

结果

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

jupyter notebook报错: No module named ‘pandas‘

打开jupyter notebook&#xff0c;新建Python3&#xff0c;编写代码import pandas as pd jupyter notebook: No module named pandas 解决办法 :打开Anaconda prompt&#xff0c;输入pip install pandas,安装时可能因为网速原因失败&#xff0c;用同样的命令再试一次&#xf…

数据透视表(二)

文章目录 导入外部数据源创建数据透视表Query 工具下的数据透视表创建如何统计业绩成交情况创建组利用函数构建辅助列创建组手动创建多样分组创建组区间统计创建组按年月日统计数据透视表的多种统计方法计算字段 导入外部数据源创建数据透视表 点击数据选项卡下数据-获取外部数…

04.FreeRTOS任务创建

04. FreeRTOS任务创建与任务删除 1. FreeRTOS创建和删除任务相关API函数 函数描述xTaskCreate()动态方式创建任务xTaskCreateStatic()静态方式创建任务xTaskCreateRestricted()动态方式创建使用 MPU 限制的任务xTaskCreateRestrictedStatic()静态方式创建使用 MPU 限制的任务…

js_拳皇(下)

文章目录 架构设计视频演示碰撞检测碰撞检测函数 构想血条和计时器全屏后续工作 架构设计 一图胜千言 #mermaid-svg-erOUDyAO5t0XgYyU {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-erOUDyAO5t0XgYyU .error-icon{…

塞尔维亚皇家科学与艺术学院向迪科维奇将军颁发奖章

2015 年 6 月 28 日&#xff0c;在托波拉文化中心礼堂&#xff0c;由塞尔维亚皇家科学家与艺术学院&#xff08;SKANU&#xff09;组织举行了一场颁奖仪式&#xff0c;向过去一年里为科学院做出无私贡献的杰出个人和集体表示感谢。 经塞尔维亚皇家科学与艺术学院一致决定&#…

RWKV 社区近期有哪些学术研究进展?

2024 年 5 月 7 日&#xff0c;我们呼吁大家使用 RWKV-6 替代 Mamba 进行科研。截至 7 月 29 日&#xff0c;来自全球各地的科研团队已经陆续发表了 7 篇基于 RWKV 架构、在各个领域进行深入研究的论文。 新的 RWKV 学术研究主要聚焦于具身智能、图像处理、模型架构三个方面。…

[Windows] 简单易用的图片去水印工具,Inpaint 9.1 单文件版

很多软件都有这个功能&#xff0c;但这个算法非常自然&#xff0c;软件小巧。 而且极为简单&#xff0c;涂鸦笔一抹&#xff0c;点绿色的《处理图像》 &#xff0c;一秒完成。 我从它6.0的版本一直用过来。现在这个是9.1 发现论坛里的 都是几年前的&#xff0c;全部都失效了。 …

【策略工厂模式】记录策略工厂模式简单实现

策略工厂模式 1. 需求背景2. 代码实现2.1 定义基类接口2.2 排序策略接口定义2.3 定义抽象类&#xff0c;实现策略接口2.4 具体的排序策略实现类2.5 实现策略工厂类2.6 控制类 3. 启动测试4. 总结 1. 需求背景 现在需要你创建一个策略工厂类&#xff0c;来根据策略实现各种排序…

达梦数据库的系统视图v$buffer_lru_first

达梦数据库的系统视图v$buffer_lru_first 达梦数据库系统视图V$BUFFER_LRU_FIRST的主要作用是显示所有缓冲区LRU链首页信息。这个视图帮助数据库管理员监控和管理缓冲池中LRU&#xff08;Least Recently Used&#xff0c;最近最少使用&#xff09;链的性能&#xff0c;通过查看…

专业级享受:2024年视频剪辑工具深度评测与推荐

说到视屏剪辑很多人都会想要到剪映吧&#xff0c;那剪映怎么剪辑视屏呢&#xff1f;剪映之外还有没有其他好用到视屏剪辑软件呢&#xff1f;这次就分享一些我自己用过到工具吧。 1.福昕视频编辑 链接直达>>https://www.pdf365.cn/foxit-clip/ 这个视频剪辑软件大大的…

【Stable Diffusion】(基础篇六)—— embedding

embedding 本系列博客笔记主要参考B站nenly同学的视频教程&#xff0c;传送门&#xff1a;B站第一套系统的AI绘画课&#xff01;零基础学会Stable Diffusion&#xff0c;这绝对是你看过的最容易上手的AI绘画教程 | SD WebUI 保姆级攻略_哔哩哔哩_bilibili 除了大模型和VAE之外…

普明服务小程序正式招募合伙人,共绘家政保洁行业新蓝图

随着家政保洁行业的快速发展和消费者对高品质服务需求的日益增长&#xff0c;普明服务小程序凭借其专业、高效、便捷的服务体验&#xff0c;迅速在市场上崭露头角。为了进一步拓展业务&#xff0c;提升品牌影响力&#xff0c;普明服务小程序现正式面向社会招募合伙人&#xff0…

你还在为PDF转Word烦恼?试试这四款免费工具吧!

悄咪咪问一句&#xff0c;大家在平时上班时最头疼的事情有哪些&#xff1f;我想会有很多朋友也有pdf如何在线转换word文档的免费方式&#xff0c;毕竟这些办公文档是非常常见的问题了&#xff0c;所以今天就专门准备这么一篇文章来分享我个人喜欢的四款好用工具&#xff1a; 第…

基于ChatGPT的“看图说话”

重磅推荐专栏: 《大模型AIGC》 《课程大纲》 《知识星球》 本专栏致力于探索和讨论当今最前沿的技术趋势和应用领域,包括但不限于ChatGPT和Stable Diffusion等。我们将深入研究大型模型的开发和应用,以及与之相关的人工智能生成内容(AIGC)技术。通过深入的技术解析和实践经…

dockerd --debugr排查服务无法启动的异常

1、查看docker服务运行状态 [rootlocalhost ~]# systemctl status docker 2、使用dockerd --debug排查错误 [rootlocalhost ~]# dockerd --debug 3、使用dockerd --debug获取的错误 4、根错误在网上查找解决方法 上图错误为二进制安装docker服务&#xff0c;/usr/local/bin/…

从里到外刨析一台电脑的性能,认识电脑很重要,妈妈再也不用担心我买电脑被骗了

现如今时代随着技术的发展&#xff0c;骗子的手段也越来越高明&#xff0c;因此从里到外刨析一台电脑的性能&#xff0c;认识电脑很重要&#xff0c;特别是准备购买电脑的小伙伴&#xff0c;建议看完这篇文章&#xff0c;其他听别人说电脑的好坏都是虚的&#xff0c;只有自己真…

创新概念:柯尔莫哥洛夫-阿诺德网络

文章目录 一、说明二、基础概念三、kolmogorov-Arnold 网络性质3.1 KAN 的潜在优势3.2 挑战和注意事项 四、基本 KAN 超参数五、COLAB 代码六、注意点 一、说明 kolmogorov-Arnold 网络 (KAN) 是深度学习领域的一项“创新”&#xff0c;它提供了一种受现有 Kolmogorov-Arnold …

【时时三省】(C语言基础)循环语句do while循环

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ——csdn时时三省 do语句的语法 do 循环语句&#xff1b; while(表达式)&#xff1b; 表达式为真继续循环 表达式为假停止 示例: break和cobtinue的运用 示例: cobtinue会跳出这个括号 到while 接着一直循…

Python 【机器学习】 进阶 之 【实战案例】房价数据中位数分析 | 1/2(含分析过程)

Python 【机器学习】 进阶 之 【实战案例】房价数据中位数分析 | 1/2&#xff08;含分析过程&#xff09; 目录 Python 【机器学习】 进阶 之 【实战案例】房价数据中位数分析 | 1/2&#xff08;含分析过程&#xff09; 一、简单介绍 二、机器学习 1、为什么使用机器学习&a…

Qt6 qml文件导入系统组件时不再需要版本号

qt开发中&#xff0c;以往在Qt5中&#xff0c;我们导入quick组件的时候总是要写版本号&#xff0c;挺麻烦的&#xff0c;而现在Qt6中qml导入组件无需再使用版本号了。直接导入即可。 import QtQuick import QtQuick.Controls import QtQuick.Window 想要看是否有这个组件&…