当前位置: 首页 > news >正文

【Linux网络编程七】网络序列化和反序列化(网络版本计算器)

【Linux网络编程七】网络序列化和反序列化(网络版本计算器)

  • 一.网络读取问题
    • 【解决方案】
    • 1.定制协议
    • 2.序列化和反序列化
    • 3.添加报头
      • ①封包
      • ②解包
    • 4.框架总结
  • 二.自定义协议:网络计算器协议
    • Ⅰ.客户端发送请求,服务器端接收请求
      • 1.构建请求(结构化数据)
      • 2.请求序列化
      • 3.添加报头,发送到网络
      • 4.服务器读取请求
      • 5.解除报头
      • 6.请求反序列化
    • Ⅱ.服务器端发送响应,客户端接收响应
      • 1.构建响应(结构化数据)
      • 2.响应序列化
      • 3.添加报头,发送到网络
      • 4.客户端读取响应
      • 5.解除报头
      • 6.响应反序列化
  • 三.自动序列化和反序列化Json
  • 四.理解OSI七层协议

一.网络读取问题

在网络通信时,通信双方是无法保证读取时,能够正确的读取到想要的内容的。
这是什么意思呢?
在这里插入图片描述

【解决方案】

在这里插入图片描述

1.定制协议

什么叫定制协议呢?就是让双方都要能知道,约定好的一些字段,然后以结构化的形式发送和接收。
在这里插入图片描述
定制的协议双方都要能认识才可以通信。不然一方认识,另一方不认识就无法通信了。
在这里插入图片描述

2.序列化和反序列化

定制好结构体后,然后构建一个对象,是不是就可以直接发送过去了呢?
当然不可以!为什么呢?

1.我们不能直接将结构体对象直接发送给对端机器,因为双方可能机器不同,对于结构体的解读会不一样,最终就会解析错误。所以通常我们不直接发送结构化数据到网络里,而是发送字符串形式的数据给对端。
2.也就是我们需要在构建完结构化数据后,在发送到网络里之前还需要将它转换成字符串形式,才能发送。这个过程就叫做序列化
3.而对端机器从网络里接收到字符串后,它并不认识这个字符串是什么意思,只有将这个字符串转成结构化化数据,它才能知道对方发送的是什么信息。而将字符串数据再转成结构化数据,就叫做反序列化。
在这里插入图片描述

在这里插入图片描述

这里是引用

3.添加报头

那么问题又回来了,对端是如何正确获取到想要的完整报文的呢?
在这里插入图片描述

我们可以利用一些特殊字符,来区别报文与报文。而如果想要对方准确的接收到一个完整的报文,那么就可以通过在报文前面添加一个长度单位,标识这个报文总长度有多少,一旦对端读取到这个长度,就可以直接从后面截取报文的长度,就可以直接完整的获取到一个报文。
而在报文前面添加一个长度单位这个行为,我们可以称为添加一个报头。

添加报头的目的就是为了让对端在读取的时候,能够根据报头,来完整的获取一个报文。所以添加报头也是属于定制协议的部分。通信的双方都要能识别。

①封包

所以构建完结构化数据后,在发送到网络之前,需要将之转换成字符串形式,也就是序列化。然后为了让对端能够准确的获取到一个完整的报文,我们还需要对这个字符串添加报头。

这里是引用

②解包

对端获取到从网络里发送来的数据后,并不理解是什么意思,所以需要反序列化,将字符串数据转换成结构化数据,这样它就可以理解是什么意思了。
但是这里存在的问题就是:它并不能确定对方发送的是一个报文还是多个报文,还是半个报文。因为从网络里发送来的就是一个字符串形式的数据。它分析不出来。而反序列化,是以一个完整的报文进行反序列化的,因为当时序列化的时候就是一个完整的结构体数据进行序列化的。

所以定制协议的人,考虑到这点,就在报文的前面添加了一个报头:表明报文的长度的字段。这样只要对端接收到报文,然后依据报头,就能分析出对方发送的数据是否是完整的了。如果是完整的,那么直接获取有效的报文。如果不是完整的,那么重新去读取,如果是多个报文,那么我们只要一个完整的报文即可。剩下的等下次再处理。

这里是引用

4.框架总结

这里是引用

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

网络部分套接字:

Socket.hpp
#pragma once
//将网络套接字编程部分直接封装打包,因为服务器和客户端都需要使用创建套接字等操作。
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include <cstdlib>
#include <cstring>
#include <unistd.h>
enum
{SocketErr=1,BindErr,ListenErr,
};
const int backlog=10;
class Sock
{public:Sock(){}~Sock(){}void Socket()//创建套接字{_socket=socket(AF_INET,SOCK_STREAM,0);if(_socket<0){lg(Fatal,"socket err:%s :%d",strerror(errno),errno);exit(SocketErr);}}void Bind(uint16_t &port)//绑定套接字{struct sockaddr_in local;memset(&local,0,sizeof(local));local.sin_addr.s_addr=INADDR_ANY;//将ip地址初始化成0local.sin_family=AF_INET;local.sin_port=htons(port);if(bind(_socket,(struct sockaddr*)&local,sizeof(local))<0){lg(Fatal,"bind err :%s :%d",strerror(errno),errno);exit(BindErr);}}void Listen()//将套接字设置成监听状态{if(listen(_socket,backlog)<0){lg(Fatal,"listen err :%s :%d",strerror(errno),errno);exit(ListenErr);}}int Accept(std::string *clientip,std::uint16_t* clientport)//服务器获取连接,并获取对方的网络信息,将获取的到的新连接交给服务函数操作{struct sockaddr_in client;socklen_t len=sizeof(client);int newsock=accept(_socket,(struct sockaddr*)&client,&len);if(newsock<0){lg(Warning,"accept err :%s :%d",strerror(errno),errno);return -1;}*clientport=ntohs(client.sin_port);char Clientip[32];inet_ntop(AF_INET,&client.sin_addr,Clientip,sizeof(Clientip));*clientip=Clientip;return newsock;}bool Connect(const std::string &serverip,const uint16_t &serverport)//需要知道要连接的对方的网络信息{struct sockaddr_in local;socklen_t len=sizeof(local);memset(&local,0,sizeof(local));local.sin_family=AF_INET;local.sin_port=htons(serverport);inet_pton(AF_INET,serverip.c_str(),&local.sin_addr);int n=connect(_socket,(struct sockaddr*)&local,len);if(n==-1){std::cerr<<"connect to"<<serverip<<":"<<serverport<<"error"<<std::endl;return false;}return true;}void Close(){close(_socket);}int Fd(){return _socket;}
private: int _socket;
};

协议部分

Protocol.hpp
#pragma once
//#define MySelf 1
// 在网络通信之前,我们服务器端和客户端都需要知道协议。我们也可以自己定制协议,这个协议要被双方都能识别
// 比如我们可以定制一个计数器协议。协议就是一种约定,除了数据本身还有其他的字段。
// 1.我们要求将数据以结构化的形式保存这样双方都可以识别这个结构体对象,但传入网络里时,需要转换成字符类型。这个过程就是序列化.序列化的过程就是在构建有效载荷
// 2.对方接收到字符串类型的数据时,想要用服务操作时,发现是不能操作的,是因为它不认识,这时还需要将字符类型转成结构体类型,这个过程叫做反序列化。
// 3.为了能让对方接收时,能接收读取到对方想要的完整报文时,我们采取添加报头的形式来解决。
// 4.所以在将报文传入到网络里时,还需要添加报文,当对端接收到报文时,想要对它进行处理之前,还需要将报文的报头解包才可以正确处理。
#include <iostream>
#include <jsoncpp/json/json.h>
#include <string>
const std::string blank_space = " ";
const std::string protocol_space="\n";
// 封包:报文在发送到网络之前需要添加一些报头,来达到一些要求
std::string Encode(const std::string &content)//content就是有效载荷
{//"x + y"------>"len"\n"x + y"\n"   添加了一个报文长度和两个\nstd::string packpage=std::to_string(content.size());packpage+=protocol_space;packpage+=content;packpage+=protocol_space;return packpage;
}// 解包:对端读取到报文(可能读取到的不是想要的,根据原先添加上去的报头来获取准确想要的报文),想要处理它,需要先解除报头才能处理
bool Decode(std::string &packpage, std::string *content)
{ //"len"\n"x + y"\n"---->"x + y"std::size_t pos=packpage.find(protocol_space);if(pos==std::string::npos)return false;std::string len_str=packpage.substr(0,pos);//判断一下是否读取的内容是全部的std::size_t len =std::stoi(len_str);std::size_t total_len=len_str.size()+len+2;if(packpage.size()<total_len)//说明不是一个完整的报文return false;*content=packpage.substr(pos+1,len);//为了真正的拿走报文,还需要将响应inbuffer里的报文移除erase,这样才是真正的拿走报文packpage.erase(0,total_len);return true;
}class Request
{
public:Request(){}Request(int data1, int data2, char op) : _x(data1), _y(data2), _op(op) // 最初形成结构化数据{}bool Serialize(std::string *out) // 序列化,单纯的就是将结构体转换成字符串{
#ifdef MySelf    // 构建报文的有效载荷// struct==》"x + y"std::string s = std::to_string(_x);s += blank_space;s += _op;s += blank_space;s += std::to_string(_y);*out = s;return true;#elseJson::Value root;//定义一个万能对象,可以存储数据,k-v形式的结构体root["x"]=_x;root["y"]=_y;root["op"]=_op;//Json::FastWriter w;Json::StyledWriter w;*out=w.write(root);//序列化成字符串return true;   #endif}bool Deserialize(std::string &in) // 反序列化,就单纯的将字符串类型转成结构体{
#ifdef MySelf   //"x + y"==>struct//获取左操作数xstd::size_t left=in.find(blank_space);if(left==std::string::npos)return false;std::string part_x=in.substr(0,left);//获取右操作数ystd::size_t right=in.rfind(blank_space);if(right==std::string::npos)return false;std::string part_y=in.substr(right+1);//获取操作码opif(left+2!=right)return false;_op=in[left+1];_x=std::stoi(part_x);_y=std::stoi(part_y);return true;
#elseJson::Value root;//定义一个万能对象,将序列化的数据存储在里面Json::Reader r;r.parse(in,root);//将数据存到万能对象里后,我们就可以根据key值找到_x=root["x"].asInt();_y=root["y"].asInt();_op=root["op"].asInt();return true;
#endif    }void DebugPrint(){std::cout<<"新请求构建完毕:"<<_x<<_op<<_y<<"=???"<<std::endl;}
public: // x + yint _x;int _y;char _op;
};
class Response
{
public:Response(int reslut, int code) : _reslut(reslut), _code(code){}Response(){}bool Serialize(std::string *out) // 序列化,单纯的就是将结构体转换成字符串{
#ifdef MySelf//"reslut code"//构建报文的有效载荷std::string s=std::to_string(_reslut);s+=blank_space;s+=std::to_string(_code);*out=s;return true;
#elseJson::Value root;root["reslut"]=_reslut;root["code"]=_code;//Json::FastWriter w;Json::StyledWriter w;*out=w.write(root);return true;
#endif    }bool Deserialize(std::string &in){
#ifdef MySelf//"reslut code"-->结构体类型std::size_t pos=in.find(blank_space);if(pos==std::string::npos)return false;std::string part_left=in.substr(0,pos);std::string part_right=in.substr(pos+1);_reslut=std::stoi(part_left);_code=std::stoi(part_right);return true;
#elseJson::Value root;Json::Reader r;r.parse(in,root);//将字符串数据存到万能对象里_reslut=root["reslut"].asInt();_code=root["code"].asInt();return true;
#endif}void DebugPrint(){std::cout<<"结果响应完成,reslut: "<<_reslut<<",code: "<<_code<<std::endl;}public:int _reslut;int _code;
};

服务器服务部分:

ServerCal.hpp
#pragma once
#include "Protocol.hpp"
#include <iostream>
#include <string>
// 服务器端,从网络里读取到数据后,就要进行处理服务。
// 1.首先需要对报文进行解包,2.解包后还需要将报文转成结构体类型对方才能识别
enum
{Div_Zero = 1,Mod_Zero,Other_Oper
} ;
class ServerCal
{
public:Response Calculatorhelpor(const Request &req){Response resp(0, 0);switch (req._op){case '+':resp._reslut = req._x + req._y;break;case '-':resp._reslut = req._x - req._y;break;case '*':resp._reslut = req._x * req._y;break;case '/':{if (req._y == 0)resp._code = Div_Zero;elseresp._reslut = req._x / req._y;}break;case '%':{if (req._y == 0)resp._code = Mod_Zero;elseresp._reslut = req._x % req._y;}break;default:resp._code=Other_Oper;break;}return resp;}std::string Calculator(std::string &package){std::string content;                //"len""\n""20 + 10""\n"bool r = Decode(package, &content); //"20 + 10"if (!r)return "";Request req; // 反序列化r = req.Deserialize(content);if (!r)return "";// 服务器端解包获取到报文后,就可以进行计算,再将计算结果返回回到网络里,网络里需要序列化的数据Response res = Calculatorhelpor(req); // reslut=30  code=0content = "";res.Serialize(&content);   //"30 0"content = Encode(content); //"len""\n""30 0""\n"return content;}
};

二.自定义协议:网络计算器协议

Ⅰ.客户端发送请求,服务器端接收请求

ClientCal.cc
#include <iostream>
#include <time.h>
#include <unistd.h>
#include <assert.h>
#include "Socket.hpp"
#include "Protocol.hpp"
void Usage(std::string proc)
{std::cout<<"\n\rUsage: "<<proc<<" port[1024+]\n"<<std::endl;
}
//./tcpclient ip port
int main(int args,char* argv[])
{if(args!=3){Usage(argv[0]);exit(1);}std::string serverip=argv[1];uint16_t serverport=std::stoi(argv[2]);Sock sockfd;sockfd.Socket();//创建套接字bool r=sockfd.Connect(serverip,serverport);//发起连接if(!r)return 1;srand(time(nullptr)^getpid());int cnt=1;std::string oper="+-*/%=$";std::string inbuffer_stream;while(cnt<=10){std::cout<<"========第"<<cnt<<"次测试"<<"============"<<std::endl;//1.开始构建请求int x=rand()%100+1;usleep(1234);int y=rand()%100;usleep(4321);char op=oper[rand()%oper.size()];Request req(x,y,op);//2.请求构建完毕req.DebugPrint();//3.数据序列化形成报文std::string content;req.Serialize(&content);//4.添加报头std::string packpage=Encode(content);//5.发送到网络里write(sockfd.Fd(),packpage.c_str(),packpage.size());//6.接收服务器端发送来的响应char buffer[128];ssize_t n=read(sockfd.Fd(),buffer,sizeof(buffer));//6.1处理读取if(n>0){buffer[n]=0;inbuffer_stream+=buffer;//接收到的是一个协议报文"len"\n"reslut code"\nstd::cout<<std::endl;std::cout<<"获取到的网络答应:"<<std::endl;std::cout<<inbuffer_stream<<std::endl;//将从网络里获取到的报文打印出来//7.首先需要解包检测std::string content;bool r =Decode(inbuffer_stream,&content);assert(r);//8.反序列化,将答应变成客户端可认识的形式Response resp;r=resp.Deserialize(content);assert(r);//9.结果响应完成resp.DebugPrint();}std::cout<<"============================="<<std::endl;sleep(1);cnt++;}sockfd.Close();
}

1.构建请求(结构化数据)

2.请求序列化

3.添加报头,发送到网络

4.服务器读取请求

5.解除报头

6.请求反序列化

Ⅱ.服务器端发送响应,客户端接收响应

Main.cc
#include "Tcpserver.hpp"
#include "ServerCal.hpp"
#include <memory>
void Usage(std::string proc)
{std::cout << "\n\rUsage: " << proc << " port[1024+]\n"<< std::endl;
}int main(int args, char *argv[])
{if (args != 2){Usage(argv[0]);exit(0);}uint16_t port = std::stoi(argv[1]);ServerCal cal;Tcpserver *tcpsvr = new Tcpserver(port, std::bind(&ServerCal::Calculator, &cal, std::placeholders::_1));tcpsvr->Init();tcpsvr->Start();return 0;
}
Tcpserver.hpp
#pragma once
#include <iostream>
#include <string>
#include <functional>
#include "Log.hpp"
#include <signal.h>
#include "Socket.hpp"
#include "ServerCal.hpp"
Sock sock;
using func_t =std::function<std::string(std::string &package)>;class Tcpserver
{public:Tcpserver(uint16_t port,func_t callback) : _port(port),_callback(callback){}bool Init(){_listensock.Socket();    // 创建套接字_listensock.Bind(_port); // 绑定套接字_listensock.Listen();    // 将套接字设置成监听状态lg(Info, "init server...done");return true;}void Start() // 启动服务器{            // 启动之前需要先忽略一些信号signal(SIGPIPE, SIG_IGN);signal(SIGCHLD, SIG_IGN);// 获取连接while (true){std::string clientip;uint16_t clientport;int sockfd = _listensock.Accept(&clientip, &clientport);if (sockfd < 0)continue;lg(Info, "accept a new link, sockfd:%d, clientip:%s ,clientport: %d",sockfd,clientip.c_str(),clientport);// 提供服务-->让子进程提供服务if (fork() == 0){_listensock.Close();std::string inbuffer_stream;while (true){// 1.读取网络中的数据流char buffer[128];size_t n = read(sockfd, buffer, sizeof(buffer));if (n > 0){buffer[n]=0;//将读取的报文进行处理inbuffer_stream+=buffer;//注意读取的内容必须是一个完整的内容,不然调用回调时,就回调用失败lg(Debug,"获取的网络请求:\n %s",inbuffer_stream.c_str());std::string info=_callback(inbuffer_stream);if(info.empty())continue;//如果进行计算时,发现报文有问题,就重新回来读取。// 2.将处理的结果发送回网络中write(sockfd,info.c_str(),info.size());}else if(n==0)break;else break;}exit(0);}close(sockfd);}}~Tcpserver(){}private:uint16_t _port;Sock _listensock;func_t _callback;
};

1.构建响应(结构化数据)

2.响应序列化

3.添加报头,发送到网络

4.客户端读取响应

5.解除报头

6.响应反序列化

三.自动序列化和反序列化Json

在这里插入图片描述

 bool Serialize(std::string *out) // 序列化,单纯的就是将结构体转换成字符串{Json::Value root;//定义一个万能对象,可以存储数据,k-v形式的结构体root["x"]=_x;root["y"]=_y;root["op"]=_op;//Json::FastWriter w;Json::StyledWriter w;*out=w.write(root);//序列化成字符串return true;  }bool Deserialize(std::string &in) // 反序列化,就单纯的将字符串类型转成结构体{Json::Value root;//定义一个万能对象,将序列化的数据存储在里面Json::Reader r;r.parse(in,root);//将数据存到万能对象里后,我们就可以根据key值找到_x=root["x"].asInt();_y=root["y"].asInt();_op=root["op"].asInt();return true;}

四.理解OSI七层协议

在这里插入图片描述

相关文章:

【Linux网络编程七】网络序列化和反序列化(网络版本计算器)

【Linux网络编程七】网络序列化和反序列化(网络版本计算器&#xff09; 一.网络读取问题【解决方案】1.定制协议2.序列化和反序列化3.添加报头①封包②解包 4.框架总结 二.自定义协议&#xff1a;网络计算器协议Ⅰ.客户端发送请求&#xff0c;服务器端接收请求1.构建请求(结构化…...

算法打卡day17|二叉树篇06|Leetcode 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树

算法题 Leetcode 654.最大二叉树 题目链接:654.最大二叉树 大佬视频讲解&#xff1a;最大二叉树视频讲解 个人思路 大概思路就是在数组中 找最大值的节点作为当前节点&#xff0c;用最大值的index切割左右子树的区间&#xff0c;往复循环到数组元素为0&#xff1b; 解法 递…...

C语言之数据在计算机内部的存储

文章目录 一、前言二、类型的基本归类1、整型家族2、浮点数家族3、构造类型4、指针类型 三、整型在内存中的存储1、原码、反码、补码1.1 概念1.2 原码与补码的转换形式1.3 计算机内部的存储编码 2、大小端介绍~~2.1 为什么要有大端和小端之分&#xff1f;2.2 大&#xff08;小&…...

程序人生——Java中基本类型使用建议

目录 引出Java中基本类型使用建议建议21&#xff1a;用偶判断&#xff0c;不用奇判断建议22&#xff1a;用整数类型处理货币建议23&#xff1a;不要让类型默默转换建议24&#xff1a;边界、边界、还是边界建议25&#xff1a;不要让四舍五入亏了一方 建议26&#xff1a;提防包装…...

Pikachu 靶场搭建

文章目录 环境说明1 Pikachu 简介2 Pikachu 安装 环境说明 操作系统&#xff1a;Windows 10PHPStudy 版本: 8.1.1.3Apache 版本&#xff1a;2.4.39MySQL 版本 5.7.26 1 Pikachu 简介 Pikachu是一个使用“PHP MySQL” 开发、包含常见的Web安全漏洞、适合Web渗透测试学习人员练…...

机器学习-绪论

机器学习致力于研究如何通过计算的手段、利用经验来改善系统自身的性能。在计算机系统中&#xff0c;“经验”通常以“数据”的形式存在&#xff0c;因此&#xff0c;机器学习所研究的主要内容&#xff0c;是关于在计算机上从数据中产生“模型”的算法&#xff0c;即“学习算法…...

mysql 索引(为什么选择B+ Tree?)

索引实现原理 索引&#xff1a;排好序的数据结构 优点&#xff1a;降低I/O成本&#xff0c;CPU的资源消耗&#xff08;数据持久化在磁盘中&#xff0c;每次查询都得与磁盘交互&#xff09; 缺点&#xff1a;更新表效率变慢&#xff0c;&#xff08;更新表数据&#xff0c;还要…...

蓝桥杯-带分数

法一 /* 再每一个a里去找c,他们共用一个st数组,可以解决重复出现数字 通过ac确定b,b不能出现<0 b出现的数不能和ac重复*/import java.util.Scanner;public class Main {static int n,res;static boolean[] st new boolean[15];static boolean[] backup new boolean[15];…...

消息队列面试题

目录 1. 为什么使用消息队列 2. 消息队列的缺点 3. 消息队列如何选型&#xff1f; 4. 如何保证消息队列是高可用的 5. 如何保证消息不被重复消费&#xff08;见第二条&#xff09; 6. 如何保证消息的可靠性传输&#xff1f; 7. 如何保证消息的顺序性&#xff08;即消息幂…...

Android和IOS应用开发-Flutter 应用中实现记录和使用全局状态的几种方法

文章目录 在Flutter中记录和使用全局状态使用 Provider步骤1步骤2步骤3 使用 BLoC步骤1步骤2步骤3 使用 GetX&#xff1a;步骤1步骤2步骤3 在Flutter中记录和使用全局状态 在 Flutter 应用中&#xff0c;您可以使用以下几种方法来实现记录和使用全局状态&#xff0c;并在整个应…...

若依 ruoyi-cloud [网关异常处理]请求路径:/system/user/getInfo,异常信息:404

这里遇到的情况是因为nacos中的配置文件与项目启动时的编码不一样&#xff0c;若配置文件中有中文注释&#xff0c;那么用idea启动项目的时候&#xff0c;在参数中加上 -Dfile.encodingutf-8 &#xff0c;保持编码一致&#xff0c;&#xff08;用中文注释的配置文件&#xff0c…...

自然语言处理里预训练模型——BERT

BERT&#xff0c;全称Bidirectional Encoder Representation from Transformers&#xff0c;是google在2018年提出的一个预训练语言模型&#xff0c;它的推出&#xff0c;一举刷新了当年多项NLP任务值的新高。前期我在零、自然语言处理开篇-CSDN博客 的符号向量化一文中简单介绍…...

2024年信息技术与计算机工程国际学术会议(ICITCEI 2024)

2024年信息技术与计算机工程国际学术会议&#xff08;ICITCEI 2024&#xff09; 2024 International Conference on Information Technology and Computer Engineering ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 大会主题&#xff1a; 信息系统和技术…...

渗透测试修复笔记 - 02 Docker Remote API漏洞

需要保持 Docker 服务运行并且不希望影响其他使用 Docker 部署的服务&#xff0c;同时需要禁止外网访问特定的 Docker API 端口&#xff08;2375&#xff09;&#xff1a;通过一下命令来看漏洞 docker -H tcp://ip地址:2375 images修改Docker配置以限制访问 修改daemon.json配…...

Spring(创建对象的方式3个)

3、Spring IOC创建对象方式一&#xff1a; 01、使用无参构造方法 //id&#xff1a;唯一标识 class&#xff1a;当前创建的对象的全局限定名 <bean id"us1" class"com.msb.pojo.User"/> 02、使用有参构造 <bean id"us2&…...

【GPT-SOVITS-02】GPT模块解析

说明&#xff1a;该系列文章从本人知乎账号迁入&#xff0c;主要原因是知乎图片附件过于模糊。 知乎专栏地址&#xff1a; 语音生成专栏 系列文章地址&#xff1a; 【GPT-SOVITS-01】源码梳理 【GPT-SOVITS-02】GPT模块解析 【GPT-SOVITS-03】SOVITS 模块-生成模型解析 【G…...

6个选品建议,改善你的亚马逊现状。

一、市场热点与需求调研 深入研究当前市场趋势&#xff0c;了解消费者需求的变化。使用亚马逊的销售数据、评价、问答等功能&#xff0c;以及第三方市场研究工具&#xff0c;比如店雷达&#xff0c;分析潜在热销产品的特点。注意季节性需求&#xff0c;提前布局相关选品&#…...

SQL中的SYSDATE函数

前言 在SQL语言中&#xff0c;SYSDATE 是一个非常实用且常见的系统内置函数&#xff0c;尤其在Oracle和MySQL数据库中广泛使用。它主要用来获取服务器当前的日期和时间&#xff0c;这对于进行实时数据记录、审计跟踪、有效期计算等场景特别有用。本文将详细解析SYSDATE函数的使…...

Rust的async和await支持多线程运行吗?

Rust的async和await的异步机制并不是仅在单线程下实现的&#xff0c;它们可以在多线程环境中工作&#xff0c;从而利用多核CPU的并行计算优势。然而&#xff0c;异步编程的主要目标之一是避免不必要的线程切换开销&#xff0c;因此&#xff0c;在单线程上下文中&#xff0c;asy…...

P2676 [USACO07DEC] Bookshelf B

[USACO07DEC] Bookshelf B 题目描述 Farmer John 最近为奶牛们的图书馆添置了一个巨大的书架&#xff0c;尽管它是如此的大&#xff0c;但它还是几乎瞬间就被各种各样的书塞满了。现在&#xff0c;只有书架的顶上还留有一点空间。 所有 N ( 1 ≤ N ≤ 20 , 000 ) N(1 \le N…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...