序列化和反序列的學習

一:重談協議

1?理解網絡協議,可以把它想象成網絡世界里的“交通規則”和“通用語言”。它是一套預先定義好的規則、標準和約定,使得不同設備、不同系統之間能夠順利地進行通信和數據交換。

我們從TCP協議上面理解一下,首先TCP服務是全雙工的,怎么理解是全雙工的呢,就是如果使用TCP服務,在客戶端或者是服務端,都有兩個緩沖區---一個是發送緩沖區,一個是接收緩沖區,我們在TCP接收發送文件不是用的是read,wirte嗎,當要接收數據時,就從接收緩沖區里讀數據交給用戶空間,也就是從內核到用戶,從而發送數據時,write函數就把用戶空間的數據拷貝到發送緩沖區里,也就是從用戶層到內核層。刷新什么的由TCP自己決定,全全交給了OS。所以TCP又叫做傳輸控制協議,里面有各種報頭來確認數據傳輸的正確性。

這個確認數據的完整性或者正確性什么的,UDP和TCP就有了各自的特點,UDP是面向報文的,相當于快遞,他就會要求傳遞報文必須是完整的,TCP是相當于自來水接水,所以呢他就有可能傳過來的數據是一段一段的,我們在報頭里就會有一些報文的長度啦,還有什么分隔符啦,分開報頭和有效載荷了什么的。而這些要求就是我們今天要說的序列化和反序列化。

二:序列化和反序列化

我們所說的協議就是一種約定,客戶端和服務端用的是同一套協議,舉個例子,假設客戶端發送請求,這個報文里面呢設置報文長度,有效載荷傳過來的數據,性別啦,年齡了等等。而服務端接收到的數據就是已經序列化好的,就是把這些數據按照一定順序排列好了給你發送過來了,接著就要把它反序列化,就是把這些存的東西一個一個的對應的從字符串里拿出來。說簡單點了就是把字符串里的內容存放在對應的結構體里。協議是一種 "約定". socket api 的接口。

實現序列化和反序列化大體上有兩種方法:

第一種就是自定義的方式,我自己規定傳過來的數據 結構是什么樣,從而讓你讀取到一個序列化好的,你可以通過反序列化拿到對應的數據,然后再返回一個序列化的結果,服務端接收到數據,也能通過反序列化拿到對應的結果

第二種方式就是用現成的?JSON 序列化 (Serialize),將內存中的數據結構(如對象、數組、字符串、數字、布爾值等)轉換成符合 JSON 格式的字符串的過程。JSON 反序列(Deserialize),將一個符合 JSON 格式的字符串 解析并轉換回內存中的數據結構(如對象、數組等)的過程。

三:使用序列化和反序列化實現一個簡單的網絡計算器

客戶端和服務端沒什么太大的變化。我們今天主要寫的就是一個序列化和反序列化

我們直接用一個JSON的,比較方便,但是你前提的安裝一下,

Ubuntu的:sudo yum install -y jsoncpp-devl

Centos的:sudo apt install -y jsoncpp-devl

1.我們需要構建兩個類,一個請求,一個應答

請求在發送之前,客戶端要進行序列化

請求在發送之后,服務端要進行反序列化

應答在發送之前,服務端要進行序列化

應答在發送之后,客戶端要進行反序列化

我們實現的計算器比較簡單 請求就是 一個數字 x 一個數字 再加一個符號,例子 30 + 20?

    int _x;int _y;char _oper;

然后把他進行序列化

     bool Serialize(std::string& out_string){Json::Value root;root["x"] = _x;root["y"] = _y;root["oper"] = _oper;Json::StreamWriterBuilder wb;std::unique_ptr<Json::StreamWriter> w(wb.newStreamWriter());std::stringstream ss;w->write(root, &ss);out_string = ss.str();return true;}

這個out_string ,是作為輸出型參數,把序列化的結果存進out_string

反序列化

 bool deserialize(std::string& in_string ){Json::Value root;Json::Reader reader;bool parsingSuccessful = reader.parse(in_string, root);if (!parsingSuccessful){return false;}_x = root["x"].asInt();_y = root["y"].asInt();_oper = root["oper"].asInt();return true;}

in_string 就是作為一個輸入型參數,把對應的結果存給對方就可以

應答的話就是一個結果,還有一個結果描述符,0設為正常,1設置為 / 或%? 0了等等,這些都可以自己約定。

private:int _result;int _code;

序列化和反序列化道理一致,我們就不再分開展示了。

完整的代碼Protocol.hpp

class Response
{public:Response() : _result(0), _code(0){}Response(int result, int code) : _result(result), _code(code){}~Response(){}bool Serialize(std::string& out_string){Json::Value root;root["result"] = _result;root["code"] = _code;Json::StreamWriterBuilder wg;std::unique_ptr<Json::StreamWriter>  w(wg.newStreamWriter());std::stringstream ss;w->write(root,&ss); //注意這里一個取地址,一個不取地址out_string = ss.str();return true;}bool deserialize(std::string& in_string){Json::Value root;Json::Reader reader;bool parsesucess = reader.parse(in_string,root);if(!parsesucess){std::cout<<"parseucess false"<<std::endl;return false;}_result = root["result"].asInt();_code = root["code"].asInt();return true;}int Result() const { return _result; }int Code() const { return _code; }void SetResult(int res) { _result = res;}void SetCode(int c) {_code = c;}private:int _result;int _code;
};

2.客戶端

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <cstdlib>
#include <string>
#include "Log.hpp"
#include "Common.hpp"
#include "Protocol.hpp"using namespace LogModule;int main(int argc , char* argv[])
{if(argc != 3 ){std::cout<<"Clinet need two arguments"<<std::endl;return 1;}std::string ip = argv[1];uint16_t port = std::stoi(argv[2]);int sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd < 0){LOG(LogLevel::ERROR) << "create scokfd false";}struct sockaddr_in peer;memset(&peer,0,sizeof(peer));peer.sin_family = AF_INET;peer.sin_port = ::htons(port);peer.sin_addr.s_addr = ::inet_addr(ip.c_str());//客戶端不用bind 綁定 ,tcp是面向連接的,connect 會自動綁定int n = ::connect(sockfd,CONV(&peer),sizeof(peer));if(n<0){LOG(LogLevel::ERROR)<<"connect false";return  1;}std::string message;while(true){int x, y;char oper;std::cout << "input x: ";std::cin >> x;std::cout << "input y: ";std::cin >> y;std::cout << "input oper: ";std::cin >> oper;Request req(x,y,oper);//序列化std::string message;req.Serialize(message);Encode(message);char inbuffer[1024];// n = ::write(sockfd, message.c_str(), message.size());n = ::send(sockfd,message.c_str(),message.size(),0);if(n > 0){//int m = ::read(sockfd, inbuffer, sizeof(inbuffer));int m =::recv(sockfd,inbuffer,sizeof(inbuffer),0);if(m > 0){inbuffer[m] = 0;std::string tmp = inbuffer;std::string content;Decode(tmp,&content);Response resp;resp.deserialize(content);std::cout<<resp.Result()<<resp.Code()<<std::endl;}elsebreak;}else break;}::close(sockfd);return 0;
}

3.服務端

TCPServer.hpp

#pragma once
#include <iostream>
#include "Common.hpp"
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <cstdlib>
#include <functional>
#include "Log.hpp"
#include "Internet.hpp"
#include "ThreadPool.hpp"#define BackWait 8using namespace LogModule;
using namespace ThreadPoolModule;
using task_t = std::function<void()>;
using handler_t = std::function<std::string(std::string& tmp)>;uint16_t defaultport = 8080;
std::string defaultip = "127.0.0.1";class TcpServer
{struct Thread {int sockfd;TcpServer* self;};
public:TcpServer(handler_t hander, uint16_t port = defaultport, std::string ip = defaultip): _port(port), _ip(ip), _isrunning(false), _listensockfd(-1),_hander(hander){}~TcpServer(){}void InitServer(){_listensockfd = ::socket(AF_INET,SOCK_STREAM,0);if(_listensockfd < 0){LOG(LogLevel::FATAL) << "create sockfd false";Die(1);}LOG(LogLevel::INFO) << "socket create success, sockfd is : " << _listensockfd;struct sockaddr_in local;bzero(&local, sizeof(local));local.sin_family = AF_INET;local.sin_port = ::htons(_port);local.sin_addr.s_addr = INADDR_ANY;// //面向連接的,還要等待隨時被連接// //所以要設置為監聽模式// 2. bindint n = ::bind(_listensockfd,CONV(&local),sizeof(local));if (n < 0){LOG(LogLevel::FATAL) << "bind error";Die(BIND_ERR);}LOG(LogLevel::INFO) << "bind success, sockfd is : " << _listensockfd;// 3. cs,tcp是面向連接的,就要求tcp隨時隨地等待被連接// tcp 需要將socket設置成為監聽狀態int m = ::listen(_listensockfd,8); if(m < 0 ){LOG(LogLevel::FATAL) <<"監聽失敗";Die(LISTEN_ERR);}LOG(LogLevel::FATAL) <<"監聽成功";}void HandlerRequest(int sockfd){char buffer[1024];std::string package;while(true){//接受消息ssize_t n = ::read(sockfd,buffer,sizeof(buffer)-1);if(n>0){buffer[n] = 0;LOG(LogLevel::DEBUG)<<"接受到消息了#:"<<buffer;package += buffer;std::string cmd_result = _hander(package);::send(sockfd, cmd_result.c_str(), cmd_result.size(), 0); // 寫入也是不完善}else if(n == 0){LOG(LogLevel::INFO) << "client quit: " << sockfd;break;}elsebreak;}}static void* ThreadHandler(void* args){//用線程也要等待回收(join) 必須等待回收的話就會阻塞,所以讓線程自己結束釋放資源pthread_detach(pthread_self());Thread* tmp = (Thread*)args;tmp->self->HandlerRequest(tmp->sockfd);return nullptr;}void Start(){_isrunning = true;while(true){struct sockaddr_in peer;socklen_t len = sizeof(peer);int sockfd = ::accept(_listensockfd,CONV(&peer),&len);//建立連接之后,這個對應的文件描述符才負責傳信(接待)if (sockfd < 0){LOG(LogLevel::WARNING) << "accept error: " << strerror(errno);continue;}LOG(LogLevel::INFO) << "accept success, sockfd is : " << sockfd;InetAddr inetaddr(peer);LOG(LogLevel::INFO) << "client info: " << inetaddr.Addr();//version 0//HandlerRequest(sockfd);// version -1 多線程版本// pid_t pid = fork();//::signal(SIGCHLD,SIG_IGN);// if(pid == 0)// {//     //子進程再創建孫子進程,子進程直接退掉,由系統進程1 來回收管理孫子進程//     //子進程和父進程 各有一張文件描述符表 文件都是通過引用計數進行管理的//     //就像管道一樣//     ::close(_listensockfd);//     if(fork() > 0)//     {//         exit(0);//     }//     HandlerRequest(sockfd);//     exit(0);// }// 給出建議父進程不要關閉文件描述符,這個設計叫權責分明// 現在語法執行沒錯,如果修改內容容易有錯// ::close(sockfd);// pid_t waitid = ::waitpid(pid,nullptr,0);// if(waitid<0)// {//     LOG(LogLevel::ERROR)<<"回收父進程失敗";// }//version 2 用多線程   // pthread_t pid;// Thread* data = new Thread;// data->self = this;// data->sockfd = sockfd;// pthread_create(&pid,nullptr,ThreadHandler,data);//version 3 線程池task_t f = std::bind(&TcpServer::HandlerRequest,this,sockfd);ThreadPool<task_t>::getInstance()->Equeue([&sockfd,this](){this->HandlerRequest(sockfd);});}}private:int _listensockfd; //這個文件描述符 只負責監聽(也就是送客人,不負責招待)uint16_t _port;std::string _ip;bool _isrunning;handler_t _hander;
};

TCPServer.cc

#include"TcpServer.hpp"
#include<memory>
#include"Log.hpp"
#include"Calculator.hpp"
#include"Protocol.hpp"
#include<functional>
#include"Daemon.hpp"using namespace LogModule;using Cal_t = std::function<Response(const Request& req)>;// using cal_fun = std::function<Response(const Request &req)>;// // package一定會有完整的報文嗎??不一定把
// // 不完整->繼續讀
// // 完整-> 提取 -> 反序列化 -> Request -> 計算模塊,進行處理class Parse
{public:Parse(Cal_t cal):_cal(cal){}std::string Entry(std::string& package){std::string message;std::string resptr;while(Decode(package,&message)){LOG(LogLevel::DEBUG) << "Content: \n" << message;if(message.empty())break;//反序列化Request req;if(!req.deserialize(message))break;//計算std::string tmp;Response resp = _cal(req);resp.Serialize(tmp);//添加長度字段Encode(tmp);//拼接應答,這樣的話有多少個需求都會處理,最后統一返回resptr+=tmp;}return resptr;}private:Cal_t _cal;
};int main()
{//ENABLE_FILE_LOG();//Daemon(false,false);Cal cal;Parse parse([&cal](const Request& req){return cal.entry(req);});std::shared_ptr<TcpServer> tserver = std::make_shared<TcpServer>([&parse](std::string &package){return parse.Entry(package);});tserver->InitServer();tserver->Start();return 0;
}

4.計算端

#include<iostream>
#include<string>
#include<memory>
#include"Protocol.hpp"class Cal
{public:Cal(){}Response entry(const Request& req){Response resp;switch (req.Oper()){case '+':resp.SetResult(req.X() + req.Y());break;case '-':resp.SetResult(req.X() - req.Y());break;case '*':resp.SetResult(req.X() * req.Y());break;case '/':{if (req.Y() == 0){resp.SetCode(1); // 1 就是除0}else{resp.SetResult(req.X() / req.Y());}}break;case '%':{if (req.Y() == 0){resp.SetCode(2); // 2 就是mod 0}else{resp.SetResult(req.X() % req.Y());}}break;default:resp.SetCode(3);break;}return resp;}private:
};

5.Log.hpp

#pragma once#include <iostream>
#include <cstdio>
#include <string>
#include <fstream>
#include <sstream>
#include <memory>
#include <filesystem> //C++17
#include <unistd.h>
#include <time.h>
#include "Mutex.hpp"
// + 日志的可變部分(<< "hello world"namespace LogModule
{using namespace Lock;std::string CurrentTime(){time_t time_stamp=::time(nullptr);struct tm curr;localtime_r(&time_stamp, &curr);char buffer[1024];snprintf(buffer,sizeof(buffer),"%4d-%02d-%02d %02d:%02d:%02d",curr.tm_year + 1900,curr.tm_mon + 1,curr.tm_mday,curr.tm_hour,curr.tm_min,curr.tm_sec);return buffer;}enum class LogLevel{DEBUG=1,INFO,WARNING,ERROR,FATAL};std::string Level2String(LogLevel level){switch (level){case LogLevel::DEBUG:return "DEBUG";case LogLevel::INFO:return "INFO";case LogLevel::WARNING:return "WARNING";case LogLevel::ERROR:return "ERROR";case LogLevel::FATAL:return "FATAL";default:return "None";}}class LogStrategy{public:virtual ~LogStrategy() = default;virtual void SyncLog(const std::string & message) = 0 ;};class ControlStrategy : public LogStrategy{public:ControlStrategy(){}~ControlStrategy(){}void SyncLog(const std::string& message){LockGuard lockguard(_mut);std::cout<<message<<std::endl;}private:Mutex _mut;};/*std::filesystem::exists(_logpath)*/const std::string defaultlogpath = "./log/";const std::string defaultlogname = "log.txt";class FileStrategy : public LogStrategy{public:FileStrategy(const std::string& logpath=defaultlogpath,const std::string& logname = defaultlogname):_logpath(logpath),_logname(logname){LockGuard lockguard(_mut);if(std::filesystem::exists(_logpath)){return;    }try{std::filesystem::create_directories(_logpath);}catch(std::filesystem::filesystem_error& t){std::cerr<<t.what()<<std::endl;}}~FileStrategy(){}void SyncLog(const std::string& message){LockGuard lockgurad(_mut);std::string log = _logpath+_logname;std::ofstream out(log,std::ios::app);if(!out.is_open()){std::cout<<"打開失敗"<<std::endl;return;}out<<message<<"\n";out.close();}private:Mutex _mut;std::string _logpath;std::string _logname;};class Logger{public:Logger(){_strategy=std::make_shared<ControlStrategy>(); }void EnableControl(){_strategy=std::make_shared<ControlStrategy>(); }void EnableFile(){_strategy=std::make_shared<FileStrategy>();}~Logger(){}//一條完整的信息: [2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [16]class LogMessage{public:LogMessage(LogLevel level,const std::string &filename, int line,Logger& logger):_time(CurrentTime()),_level(level),_pid(::getpid()),_name(filename),_line(line),_logger(logger){std::stringstream ssbuffer;ssbuffer << "[" << _time << "] "<< "[" <<Level2String(_level) << "] "<< "[" << _pid << "] "<< "[" << _name << "] "<< "[" << _line << "] - ";_loginfo = ssbuffer.str();//std::cout<<_loginfo<<std::endl;         }template<class T>LogMessage &operator<<(const T& info){std::stringstream ss;ss<<info;_loginfo += ss.str();return *this;}~LogMessage(){if(_logger._strategy){_logger._strategy->SyncLog(_loginfo);}}private:std::string _time;LogLevel _level;;pid_t _pid;std::string _name;int _line;std::string _loginfo;Logger &_logger;};LogMessage operator()(LogLevel level, const std::string &filename, int line){return LogMessage(level, filename, line,*this);}private:std::shared_ptr<LogStrategy> _strategy;};Logger logger;
#define LOG(level) logger(level,__FILE__,__LINE__)
#define ENABLE_CONSOLE_LOG() logger.EnableControl()
#define ENABLE_FILE_LOG() logger.EnableFile()}

四 重談七層協議

五層協議: 物理層? 數據鏈路層 網絡層?應用層? 傳輸層?

七層協議:物理層? 數據鏈路層? 網絡層?應用層? 傳輸層? 會話層 表示層

五層模型是將 OSI 七層模型中的會話層、表示層和應用層這三層合并成了一個單一的應用層。

為什么這樣合并?
實際應用:在實際的 TCP/IP 協議棧中,會話管理(如建立、管理和終止會話)和數據表示(如數據加密、壓縮、格式轉換)的功能通常由應用程序本身或應用層協(如 HTTP、TLS/SSL)來實現,而不是由一個獨立的、通用的協議層來處理。也就是說應用層實現大部分,所以為了不沖突,就由用戶層自我決定。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/94883.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/94883.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/94883.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

計算機畢業設計 java 在線學習系統 基于 Java 的在線教育平臺 Java 開發的學習管理系統

計算機畢業設計 java 在線學習系統fk01a40i &#xff08;配套有源碼 程序 mysql數據庫 論文&#xff09;本套源碼可以先看具體功能演示視頻領取&#xff0c;文末有聯xi 可分享傳統學習模式受時空限制&#xff0c;互動性不足&#xff0c;難以滿足個性化學習需求。為打破限制&…

淘寶利用商品關鍵詞獲取商品信息指南

一、核心API接口選擇接口名稱功能描述適用場景taobao.items.search通過關鍵詞搜索商品&#xff0c;支持分頁、排序&#xff0c;返回商品列表&#xff08;含標題、價格、銷量、圖片等&#xff09;普通商品搜索、競品監控、數據分析taobao.tbk.item.get淘寶客API&#xff0c;返回…

紅黑樹下探玄機:C++ setmultiset 的幕后之旅

目錄 一、關聯式容器 二、鍵值對 三、set 四、set的構造 五、set的iterator 六、set的Operations 七、multiset 一、關聯式容器 序列式容器 &#xff1a; 在初階階段&#xff0c;我們已經接觸過STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque、forwa…

Spring : 事務管理

1. 基本概念 事務&#xff08;Transaction&#xff09;是一組不可分割的操作單元&#xff0c;這些操作要么全部成功執行&#xff0c;要么全部失敗回滾&#xff0c;不存在部分成功的情況。 事務具有ACID特性&#xff1a; 原子性&#xff08;Atomicity&#xff09;&#xff1a;事…

C# 一個投資跟蹤程序的設計與實現:面向對象與設計模式的深度解析

在現代金融應用開發中&#xff0c;如何高效、靈活地構建投資跟蹤系統&#xff0c;是每一個金融軟件工程師必須面對的挑戰。本文將圍繞一個投資跟蹤程序的設計與實現過程&#xff0c;深入剖析其背后的設計理念、架構模式以及具體實現細節。我們將通過面向對象編程、設計模式&…

存儲的未來之戰:RustFS如何用ZK框架重構分布式協調?

本篇文章目錄 一、導火索&#xff1a;當數據洪峰撞上分布式協調的天花板 二、技術密碼&#xff1a;ZK框架的三大重構 2.1 一致性哈希環的量子級進化 2.2 動態負載均衡的"神經反射" 2.3 跨云數據同步的"時空折疊" 三、未來戰爭&#xff1a;2026年存儲…

模擬實現STL中的list容器

list前言一、list的節點結構設計二、迭代器設計三、list類的實現3.1 類的成員變量和類型定義3.2 構造函數與析構函數3.3 元素訪問與迭代器接口3.4 插入與刪除操作3.5 其他常用操作四、總結每文推薦前言 在C STL中&#xff0c;list是一個非常常用的容器&#xff0c;它基于雙向循…

Debug-039-el-date-picker組件手動輸入時間日期的問題處理

圖1-外輸入框圖2-內輸入框圖3問題描述&#xff1a;這兩天在迭代功能的時候&#xff0c;基本上碰到的問題都是出自這個“時間日期選擇框”&#xff0c;昨天的bug38也是解決這個組件。如上圖1和2所示&#xff0c;可以把圖1中的輸入框叫外輸入框&#xff0c;圖2中的輸入框叫內輸入…

docker-runc not installed on system

問題 Docker build時Dockerfile有RUN命令執行報錯shim error: docker-runc not installed on system&#xff0c;如下&#xff1a;解決方法 修改/etc/docker/daemon.json&#xff0c;添加正面內容 {"runtimes": {"docker-runc": {"path": "…

【秋招筆試】2025.08.27華為秋招研發崗真題

?? 點擊直達筆試專欄 ??《大廠筆試突圍》 ?? 春秋招筆試突圍在線OJ ?? 筆試突圍在線刷題 bishipass.com 題目一:智能溫控系統監測 1??:使用滑動窗口技術維護有效溫度區間 2??:利用單調隊列高效維護窗口內的最大值和最小值 3??:動態調整窗口邊界,確保滿足溫…

Kafka 消費模型

文章目錄1. 一個消費者組中只有 1 個消費者2. 一個消費者組中有 2 個消費者3. 消費者數量 > 分區數量4. 多個消費者讀取同一個分區5. 消費者放入消費者組5.1 何時放入同一個消費者組5.2 何時放入不同的消費者組1. 一個消費者組中只有 1 個消費者 假設我們有一個 TopicT1&am…

【路由器】TP Link 路由器為何無法進入管理后臺

TL-WR710N是TP Link在很多年前發布的一個迷你型的便攜路由器&#xff0c;一插上還能用&#xff0c;直接reset打算重設密碼&#xff0c;結果根據它給的192.168.1.253根本打不開。# 解決方法ping一下192.168.1.253&#xff0c;無法連接。這個問題本質上是 你電腦/手機的 IP 和路由…

LightGBM(Light Gradient Boosting Machine,輕量級梯度提升機)梳理總結

LGB微軟團隊在 2017 年提出的梯度提升樹模型&#xff0c;核心定位是 “更高效的 XGBoost”—— 它在保持精度接近 XGBoost 的同時&#xff0c;通過“數據采樣優化”“特征壓縮”“樹生長策略改進”三大創新&#xff0c;將訓練速度提升 10-100 倍&#xff0c;內存消耗降低數倍&a…

畢業項目推薦:29-基于yolov8/yolov5/yolo11的光伏板檢測識別系統(Python+卷積神經網絡)

文章目錄 項目介紹大全&#xff08;可點擊查看&#xff0c;不定時更新中&#xff09;概要一、整體資源介紹技術要點功能展示&#xff1a;功能1 支持單張圖片識別功能2 支持遍歷文件夾識別功能3 支持識別視頻文件功能4 支持攝像頭識別功能5 支持結果文件導出&#xff08;xls格式…

【實時Linux實戰系列】實時數據可視化技術實現

在當今數據驅動的世界中&#xff0c;實時數據可視化已成為理解和利用實時信息的關鍵工具。無論是在金融交易監控、工業生產監控、智能交通管理還是物聯網設備監控中&#xff0c;能夠將復雜的數據以直觀的圖表形式展示出來&#xff0c;對于快速決策和問題解決至關重要。實時數據…

【LeetCode每日一題】21. 合并兩個有序鏈表 2. 兩數相加

每日一題21. 合并兩個有序鏈表題目總體思路算法步驟時間復雜度與空間復雜度代碼2. 兩數相加題目總體思路算法步驟時間復雜度與空間復雜度代碼知識感悟2025.8.3021. 合并兩個有序鏈表 題目 將兩個升序鏈表合并為一個新的 升序 鏈表并返回。新鏈表是通過拼接給定的兩個鏈表的所…

DVWA靶場通關筆記-文件包含(Impossible級別)

目錄 一、源碼分析 二、文件包含防范分析 1、明確指定允許包含的文件 2、拒絕所有未在白名單中的輸入 3、總結 &#xff08;1&#xff09;白名單 (Allow List) &#xff08;2&#xff09;硬編碼/映射 (Hardcoding/Mapping) &#xff08;3&#xff09;輸入過濾 (Input F…

構建堅不可摧的數據堡壘:深入解析 Oracle 高可用與容災技術體系

在當今數字化時代&#xff0c;數據是企業的核心資產&#xff0c;而承載這些數據的數據庫系統的連續性與穩定性直接關系到企業的生死存亡。一次計劃外的停機或災難性的數據丟失&#xff0c;帶來的不僅是經濟上的巨大損失&#xff0c;更是對品牌信譽和客戶信任的致命打擊。因此&a…

【3D算法技術入門】如何基于建筑圖片重建三維數字資產?

要基于建筑圖片重建三維數字資產是一個復雜的計算機視覺任務&#xff0c;涉及圖像采集、特征提取、相機姿態估計、稠密重建和三維模型優化等多個步驟。下面我將提供一個基于Python的解決方案框架&#xff0c;使用開源庫實現從圖片到三維模型的基本流程。 首先需要安裝必要的庫&…

?CVPR2025 自動駕駛半監督 LiDAR 分割新范式:HiLoTs 框架深度解析

&#x1f4c4;論文題目&#xff1a;HiLoTs: High-Low Temporal Sensitive Representation Learning for Semi-Supervised LiDAR Segmentation in Autonomous Driving ??作者及機構&#xff1a; R.D. Lin、Pengcheng Weng、Yinqiao Wang、Fei Wang&#xff08;西安交通大學軟件…