沧州网站建设公司/百度投放广告
欢迎来到Cefler的博客😁
🕌博客主页:折纸花满衣
🏠个人专栏:题目解析
🌎推荐文章:C++【智能指针】
前言
在正式代码开始前,会有一些前提知识引入
目录
- 👉🏻序列化和反序列化
- 👉🏻三次握手和四次挥手
- 👉🏻一些概念知识
- 全双工
- TCP和UDP对比
- send和recv
- 👉🏻TCP通信-使用相同结构化字段传输数据(但未真正的序列化和反序列化)
- Protocol.hpp(协议内容)
- Socket.hpp(封装socket通信的功能)
- TcpServer.hpp(封装服务端功能)
- TcpServerMain.cc
- TcpClientMain.cc
- 实现效果
👉🏻序列化和反序列化
在网络应用层中,序列化(Serialization)和反序列化(Deserialization)是将数据转换为可在网络上传输的格式,并从网络接收的数据恢复为本地数据结构的过程。
🌈序列化(Serialization):
序列化是将数据对象转换为一系列字节的过程,以便在网络上传输或存储到磁盘上。序列化的目标是创建一个可以被发送到其他系统或进程,并且能够被正确解释和还原的数据表示形式。在网络应用中,常见的序列化格式包括JSON(JavaScript Object Notation)、XML(eXtensible Markup Language)、Protocol Buffers、MessagePack等。
序列化的过程通常涉及以下步骤:
- 选择序列化格式:根据数据的特性和需求选择合适的序列化格式。
- 定义数据结构:确定要序列化的数据对象的结构,并为其定义序列化规则。
- 将数据转换为字节流:根据所选的序列化格式,将数据对象转换为字节流。
- 传输或存储:将序列化后的字节流发送到网络或者存储到磁盘上。
🌈反序列化(Deserialization):
反序列化是将序列化后的数据流转换回原始数据对象的过程。在接收到网络传输的数据后,需要对其进行反序列化以还原成原始数据对象。
反序列化的过程通常包括以下步骤:
- 接收数据流:从网络或者磁盘读取序列化后的数据流。
- 解析数据:根据所选的序列化格式,解析字节流并将其转换为数据对象。
- 数据还原:根据序列化规则和数据结构,将解析后的数据转换为原始数据对象。
- 应用数据:将还原后的数据对象用于应用程序的后续处理。
序列化和反序列化在网络通信中扮演着重要的角色,它们允许不同系统之间以统一的方式进行数据交换,同时也提供了数据传输的可靠性和可扩展性。
📒 一个小故事理解序列化和反序列化
故事标题:糖果工厂的序列化奇遇
一天,糖果工厂的老板决定向全球各地拓展市场,他决定使用一种特殊的糖果序列化器来包装他的糖果,以确保它们在长途运输中保持新鲜和美味。
序列化器(Serializationizer)是一台神奇的机器,它可以将任何形状、口味的糖果转换成一种特殊的串口糖果,这种串口糖果可以轻松地传输到世界各地,并在需要时还原为原始的糖果。
老板向工厂的工程师们解释了他的计划,然后开始了序列化器的操作。首先,他们把一袋五彩斑斓的糖果放进了序列化器中,它发出了一声“嘟噜嘟噜”的声音,然后从另一端输出了一串光滑而有序的串口糖果。
工程师们快乐地向老板展示他们的成果,老板也很满意。于是,他们将这些串口糖果装进了特殊的包装盒,准备发往全球各地的客户。
然而,一名新来的工程师在整理文件时不小心碰到了序列化器的控制台,他误触了一个按钮,导致序列化器的设置发生了改变。
于是,下一个批次的糖果被转换成了一种奇怪的形状,颜色也变得混乱不堪。这些串口糖果被送到了全球各地,但客户们收到后都表示了不满,称他们从未见过如此奇特的糖果。
老板赶紧调查了原因,发现了新工程师的失误。他们及时纠正了序列化器的设置,重新开始了正常的生产。这次,他们确保了每个糖果被正确序列化,而不是变成了像乱七八糟的串口糖果。
结局: 糖果工厂重新获得了客户的信任,全球各地的人们再次享用到了美味的糖果。而那位新工程师也从这个经历中学到了重要的教训:在操作序列化器时一定要小心,否则可能会引发一场糖果灾难!
👉🏻三次握手和四次挥手
当建立和终止TCP连接时,通常会执行三次握手(Three-Way Handshake)和四次挥手(Four-Way Handshake)的过程,以确保通信的可靠性和正确性。
🌈三次握手(Three-Way Handshake):
-
客户端发送同步序列号(SYN)报文:
- 客户端首先向服务器发送一个带有SYN标志的报文,表示客户端请求建立连接,并选择一个初始的序列号(Sequence Number)。
-
服务器确认连接请求:
- 服务器收到客户端的SYN报文后,会发送一个带有SYN和ACK标志的报文,表示同意建立连接,并确认收到了客户端的连接请求,并选择自己的初始序列号。
-
客户端确认连接:
- 客户端收到服务器的SYN+ACK报文后,会发送一个带有ACK标志的报文给服务器,表示确认连接建立。
这样,客户端和服务器之间的TCP连接就建立起来了,可以开始进行数据传输。
🌈 四次挥手(Four-Way Handshake):
-
客户端发送关闭连接请求:
- 客户端发送一个带有FIN(结束)标志的报文给服务器,表示客户端不再发送数据,但仍愿意接收数据。
-
服务器确认关闭请求并关闭数据传输:
- 服务器收到客户端的FIN报文后,会发送一个带有ACK标志的报文给客户端,表示确认关闭请求,并停止向客户端发送数据,但仍可以接收数据。
-
服务器发送关闭连接请求:
- 服务器发送一个带有FIN标志的报文给客户端,表示服务器也准备关闭连接。
-
客户端确认关闭请求并关闭连接:
- 客户端收到服务器的FIN报文后,会发送一个带有ACK标志的报文给服务器,表示确认关闭请求,并关闭连接。
这样,客户端和服务器之间的TCP连接就完全关闭了。四次挥手的过程中,双方都可以发送数据,并且在关闭连接后都不能再发送数据。
📒 一个小例子理解三次握手和四次挥手
好的,让我们用一种有趣的方式来理解三次握手和四次挥手。
🫱🏻🫲🏻 三次握手(Three-Way Handshake):
想象一下你和朋友约好去吃披萨。这里有个名叫小明的朋友(客户端)和一个叫披萨店的地方(服务器)。
-
小明: “嗨,披萨店老板!我想要一份披萨!”(发送SYN)
-
披萨店老板: “好的,小明,你想要什么口味的披萨?”(发送SYN+ACK)
-
小明: “我想要意大利香肠披萨!”(发送ACK)
现在,小明和披萨店之间建立了连接,披萨店知道了小明的口味,准备开始制作披萨。
🤲🏻 四次挥手(Four-Way Handshake):
披萨终于做好了,大家都吃得很开心,然后就是结束这次美好的披萨时光。
-
小明: “披萨店老板,谢谢你的披萨,我不想再点了!”(发送FIN)
-
披萨店老板: “不客气,小明,欢迎下次再来!披萨店休息了!”(发送ACK)
-
披萨店老板: “好了,披萨店打烊了,我们关门了!”(发送FIN)
-
小明: “明白了,披萨店老板,再见!”(发送ACK)
这样,小明和披萨店之间的交流就结束了,披萨店可以关门休息了,而小明也满足地离开了。
👉🏻一些概念知识
全双工
全双工(Full Duplex)是指数据通信系统中能够同时实现双向通信的能力,即在同一时间点上可以同时进行发送和接收数据的操作。这种模式下,通信双方能够同时进行双向数据传输,而不需要等待对方完成发送或接收操作。
在全双工通信中,发送和接收数据的通道是完全独立的,彼此之间互不干扰。这意味着通信双方可以在不同的频率或者不同的频道上同时进行通信,而不会造成碰撞或数据丢失。
全双工通信通常用于需要高速、实时双向数据传输的场景,比如电话通话、视频会议、网络通信等。相比于半双工通信(Half Duplex),全双工通信具有更高的通信效率和更低的延迟,因为它允许发送和接收数据同时进行,而不需要等待切换操作。
在网络通信中,全双工模式通常通过使用不同的通信频率(如Wi-Fi、蓝牙等无线通信)、不同的通信信道(如以太网的双绞线)或者使用不同的时隙(如时分多址技术)来实现。这种模式在现代通信技术中被广泛应用,为用户提供了更流畅、更高效的通信体验。
TCP和UDP对比
TCP(传输控制协议)和UDP(用户数据报协议)是两种常用的网络传输协议,它们在数据传输时有着不同的特点和适用场景:
-
连接性:
- TCP是面向连接的协议,它在通信双方建立连接后才能进行数据传输,确保数据的可靠性和顺序性。
- UDP是无连接的协议,通信双方无需建立连接即可直接发送数据,因此不保证数据的可靠性和顺序性。
-
可靠性:
- TCP提供可靠的数据传输,通过序号、确认和重传机制来确保数据的完整性和可靠性,保证数据不会丢失或损坏。
- UDP不提供可靠性保证,数据包可能会丢失、重复或者乱序,因此在一些实时性要求高、但对数据完整性要求较低的场景下使用较多。
-
流量控制(面向字节流)和拥塞控制:
- TCP通过流量控制和拥塞控制机制来调节数据传输速率,以避免网络拥塞和数据丢失。
- UDP不提供流量控制和拥塞控制,数据传输速率由发送方直接决定,可能会导致网络拥塞。
-
适用场景:
- TCP适用于需要可靠数据传输和顺序传输的场景,如文件传输、网页浏览、电子邮件等。
- UDP适用于实时性要求高、但对数据完整性要求较低的场景,如音频和视频流、在线游戏、实时通信等。
-
开销:
- TCP的头部开销较大,包含了序号、确认、窗口大小等信息,因此在传输小量数据时可能会存在较大的开销。
- UDP的头部开销较小,只包含了源端口、目标端口、长度和校验和等基本信息,因此在传输小量数据时开销较小。
总的来说,TCP提供了可靠的数据传输和顺序传输,适用于对数据完整性要求高的场景;而UDP提供了更快速的数据传输和更低的开销,适用于实时性要求高、但对数据完整性要求较低的场景。选择使用哪种协议取决于具体的应用需求和性能要求。
send和recv
当编写网络程序时,常用的函数之一是send
和recv
,它们通常用于在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套接字,因此它们也是基于已连接的。
总的来说,send
和recv
函数适用于TCP连接,而sendto
和recvfrom
函数适用于UDP套接字。前者是基于连接的,后者是无连接的。
👉🏻TCP通信-使用相同结构化字段传输数据(但未真正的序列化和反序列化)
代码目录:
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;elsereturn 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】应用层协议序列化和反序列化
欢迎来到Cefler的博客😁 🕌博客主页:折纸花满衣 🏠个人专栏:题目解析 🌎推荐文章:C【智能指针】 前言 在正式代码开始前,会有一些前提知识引入 目录 👉🏻序列…...

使用Canal同步MySQL 8到ES中小白配置教程
🚀 使用Canal同步MySQL 8到ES中小白配置教程 🚀 文章目录 🚀 使用Canal同步MySQL 8到ES中小白配置教程 🚀**摘要****引言****正文**📘 第1章:初识Canal1.1 Canal概述1.2 工作原理解析 📘 第2章&…...

关于部署ELK和EFLK的相关知识
文章目录 一、ELK日志分析系统1、ELK简介1.2 ElasticSearch1.3 Logstash1.4 Kibana(展示数据可视化界面)1.5 Filebeat 2、使用ELK的原因3、完整日志系统的基本特征4、ELK的工作原理 二、部署ELK日志分析系统1、服务器配置2、关闭防火墙3、ELK ElasticSea…...

实验室信息系统源码 saas模式java+.Net Core版开发的云LIS系统全套源码可二次开发有演示
实验室信息系统源码 saas模式java.Net Core版开发的云LIS系统全套源码可二次开发有演示 一、技术框架 技术架构:Asp.NET CORE 3.1 MVC SQLserver Redis等 开发语言:C# 6.0、JavaScript 前端框架:JQuery、EasyUI、Bootstrap 后端框架&am…...

PCB---Design Entry cis 绘图 导出
修改纸张大小: 画图前准备:导入 画图: 习惯: 电源朝上 地朝下 配置pbc_footprint编号: 都配置好编号就可以导出了 导出:...

vue 一键更换主题颜色
这里提供简单的实现步骤,具体看自己怎么加到项目中 我展示的是vue2 vue3同理 在 App.vue 添加 入口处直接修改 #app { // 定义的全局修改颜色变量--themeColor:#008cff; } // 组件某些背景颜色需要跟着一起改变,其他也是同理 /deep/ .ant-btn-primar…...

WebKit内核游览器
WebKit内核游览器 基础概念游览器引擎Chromium 浏览器架构Webkit 资源加载这里就不得不提到http超文本传输协议这个概念了: 游览器多线程HTML 解析总结 基础概念 百度百科介绍 WebKit 是一个开源的浏览器引擎,与之相对应的引擎有Gecko(Mozil…...

Qt 拖放功能详解:理论与实践并举的深度指南
拖放(Drag and Drop)作为一种直观且高效的用户交互方式,在现代图形用户界面中扮演着重要角色。Qt 框架提供了完善的拖放支持,允许开发者在应用程序中轻松实现这一功能。本篇博文将详细阐述Qt拖放机制的工作原理,结合详…...

Springboot+Vue项目-基于Java+MySQL的企业客户管理系统(附源码+演示视频+LW)
大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &…...

【Linux学习】Linux指令(四)
文章标题 🚀zip/unzip指令:🚀tar指令(重要):🚀uname –r指令:🚀关机指令🚀几个常用操作 🚀zip/unzip指令: zip 与 unzip的安装 yum i…...

阿里云服务器 使用Certbot申请免费 HTTPS 证书及自动续期
前言 Certbot是一款免费且开源的自动化安全证书管理工具,由电子前沿基金会(EFF)开发和维护,是在Linux、Apache和Nginx服务器上配置和管理SSL/TLS证书的一种机制。Certbot可以自动完成域名的认证并安装证书。 一、 安装软件 1.1…...

统一SQL-number/decimal/dec/numeric转换
统一SQL介绍 https://www.light-pg.com/docs/LTSQL/current/index.html 源和目标 源数据库:Oracle 目标数据库:Postgresql,TDSQL-MySQL,达梦8,LightDB-Oracle 操作目标 通过统一SQL,将Oracle中的numb…...

软件测试入门学习笔记
系统测试流程规范 一.研发模型 1.瀑布模型 从可行性研究(或系统分析)开始,需求 2.增量迭代模型 3.敏捷开发模型 二.质量模型...

31. 下一个排列
题目描述 整数数组的一个排列 就是将其所有成员以序列或线性顺序排列。 例如,arr [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。 整数数组的下一个排列是指其整数的下一个字典序更大的排列。更正式地&…...

Android笔记: mkdirs不生效失败
Manifest已经配置权限,代码中也动态获取权限,mkdirs一直返回false File.mkdirs()方法创建文件夹失败 1、动态申请读写权限 <!--SDCard写权限--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!--SDCard读权…...

需要添加的硬币的最小数量(Lc2952)——贪心+构造
给你一个下标从 0 开始的整数数组 coins,表示可用的硬币的面值,以及一个整数 target 。 如果存在某个 coins 的子序列总和为 x,那么整数 x 就是一个 可取得的金额 。 返回需要添加到数组中的 任意面值 硬币的 最小数量 ,使范围 …...

军工保密资质介绍及申请要求
军工保密资质介绍 军工保密资质是指国家对从事军工研发、生产、销售等活动的企事业单位进行的一种资质认证。该资质的核心目标是保护国家军事机密和军事技术秘密,确保国家安全和国防利益。军工保密资质的认证标准非常严格,涉及企业的安全管理、技术保密…...

ES6的编程风格
ES6 提出了两个新的声明变量的命令:let和const。其中,let完全可以取代var,因为两者语义相同,而且let没有副作用。 var命令存在变量提升效用,let命令没有这个问题 if (true) {console.log(x); // ReferenceErrorlet x…...

springboot 载入自定义的yml文件转DTO
json解析的pom引入 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-json</artifactId><version>5.8.20</version></dependency>resources目录下的my-data.yml project:data:- name: service-genbase-package:…...

webpack-(plugin,本地服务器,路径别名,安装vue)
安装vue npm i vue-loader -D npm i vue 编写一个vue文件: 在index.html中设置 一个id为app的div 将vue文件挂载到app中 vue比较特殊,除了使用loader外,还使用了plugin const path require("path"); const { VueLoaderPlugin …...

http请求头导致了dial tcp:lookup xxxx on 10.43.0.10:53 no sunch host
事实证明人有的时候也不能太偷懒,太偷懒容易给自己埋坑。 问题的背景: web端调用服务A,服务A异步调用服务B。服务A有四个场景需要调用服务B,所以,服务A中封装了一个公用的方法,唯一的区别是,场…...

想要设计放大电路,必须掌握哪些?
放大电路是电子系统中的核心组成部分,其设计好坏将直接影响到整个系统的性能,对电子工程师来说,在设计放大电路时,必须掌握且关注多方面,以此确保电路的稳定性和放大效果,那么需要注意哪些? 1、…...

每天五分钟计算机视觉:基于卷积操作完成滑动窗口的图片分类?
本文重点 我们前面学习了使用不同大小的滑动窗口来滑动图片,然后切分成许多小的图片,然后依次应用到我们已经训练好的图像分类模型中,但是这种方式效率太低了,本节课程我们学习一种新的方式,来看一下如何并行识别这些剪切的图片。 原始结构 首先我们先来看一下,如何把…...

UI设计/交互设计/视觉设计项目汇报/作品集Figma/PPT模板
作为UI设计/交互设计/视觉设计师,创建作品集对于向潜在客户或雇主展示您的技能、创造力和风格至关重要。以下分步指南可帮助您创建令人印象深刻的作品集: 选择您的最佳作品:选择您最强大且最相关的设计项目,将其纳入您的作品集。…...

25、Lua 学习笔记之三(高阶话题)
Lua 学习笔记之三 高阶话题迭代实例代码有关迭代的描述 协作线程实例代码有关协作线程的描述 高阶话题 迭代 实例代码 --迭代 local function enum(array)local index 1return function()local ret array[index]index index 1return retend endlocal function foreach(a…...

企业网盘搭建——LNMP
php包链接:https://pan.baidu.com/s/1RElYTQx320pN6452N_7t1Q?pwdp8gs 提取码:p8gs 网盘源码包链接:https://pan.baidu.com/s/1BaYqwruka1P6h5wBBrLiBw?pwdwrzo 提取码:wrzo 目录 一.手动部署 二.自动部署 一.手动部署 …...

Go语言异常处理方式
Go 语言没有传统的异常处理机制,如 Java、C 或 Python 中的 try-catch 语句。取而代之,Go 采用了基于返回错误值和 panic/recover 机制的混合模式来进行错误处理。以下是 Go 语言中处理异常(或称错误)的两种主要方式: …...

时序分析基本知识点
【FPGA开发/IC开发之时序约束最全面的归纳总结】时序路径基本概念及时序约束分析方法_时序约束指令-CSDN博客...

ELK(Elasticsearch+Logstash+Kibana)日志分析系统
目录 前言 一、ELK日志分析系统概述 1、三大组件工具介绍 1.1 Elasticsearch 1.1.1 Elasticsearch概念 1.1.2 关系型数据库和ElasticSearch中的对应关系 1.1.3 Elasticsearch提供的操作命令 1.2 Logstash 1.2.1 Logstash概念 1.2.2 Logstash的主要组件 1.2.3 Logsta…...

【投稿优惠-EI稳定检索】2024年地理信息技术与遥感测绘国际学术会议(ICGITRSM 2024)
2024 International Conference on Geographic Information Technology and Remote Sensing Mapping (ICGITRSM 2024) ●会议简介 2024年地理信息技术与遥感测绘国际学术会议将聚焦于地理信息技术及遥感测绘领域的最新发展与应用。本次会议汇聚了来自世界各地的顶尖专家和学者…...