【Linux进阶之路】网络 —— “?“ (下)
文章目录
- 前言
- 一、概念铺垫
- 1.TCP
- 2.全双工
- 二、网络版本计算器
- 1. 原理简要
- 2. 实现框架&&代码
- 2.1 封装socket
- 2.2 客户端与服务端
- 2.3 封装与解包
- 2.4 请求与响应
- 2.5 对数据进行处理
- 2.6 主程序逻辑
- 3.Json的简单使用
- 总结
- 尾序
前言
在上文我们学习使用套接字的相关接口进行了编程,因此对网络编程有了一定的认识,可是我们之前只是以字符串的形式简单的收发信息,如果我们要发送和接受的信息更加复杂,比如:客户端发送一个结构体,服务端要如何接收这个结构体呢? 如果说还要对结构体的数据进行处理并返回呢?下面就让我们带着这些疑问开始今天的学习吧!
- 说明:
- 每台计算机的结构体的对齐方式可能会有所不同,因此不能直接发送结构体。
- 因此要将结构体里的数据要以特定的形式,即协议的方式发送和接收。
- 对数据处理后,还要以协议的方式发送给客户端,从而客户端收到并进行对应的处理。
一、概念铺垫
1.TCP
- 众所周知,TCP是可靠的传输控制协议,一般是通过三次握手和四次挥手来保证数据的传输是可靠的。
- 说明:下面只是简单的理解,后面博主详细讲解的。
- 三次握手 :
- 三次交互,建立连接。
- 四次挥手:
- 断开连接,就是要断的干净,避免之后一方进行死缠烂打。
2.全双工
- 所谓的全双工,就是服务端和客户端都是可以收消息和发消息的,例如UDP和TCP协议都是全双工的。
- UDP
- TCP
- 理解传输控制协议:
- 对于UDP来说,在传输层对于发消息不做控制,但是对于收消息如何处理,则全权交由UDP决定。
- 对于TCP来说,用户只负责将消息发送到发送和接收缓存区,但对于消息如何处理,则全权由TCP决定。
- 说明:处理一般涉及什么时候传,传多少,传错了怎么办等等。
- 从UDP与TCP相比较,TCP多了一个发送缓冲区,这在一定程度上可以体现TCP的可靠性。
二、网络版本计算器
1. 原理简要
- 因为我们做的是网络版本的计算器,数据格式设定为
[ 数据(空格)方法(空格)数据(换行符)]
即可,而且在网络中我们一般是以字符串的形式进行发送的,因此我们还要将整形数据转换为字符串,便于之后的解析。- 数据的封装,为了能将
一个完整的
数据解析出来,因此我们应该在数据的前面封装数据的长度
,当截取数据时,我们按照长度截取即可检查是否可获取到一个完整的数据,并且长度应与数据分开,便于获取,这里我们用换行符作为分割符
即可。这里实现了数据的封装也就间接的实现了对数据解包。
- 举一个体现自定义协议的例子,比如 [1 + 1]封装为 [5\n][1 + 1\n],数据按上面的封装,而服务器读取时,假如只读取到了[5\n 1 +],通过读取5这个字符串,转换为int,可以验证读取的报文是否是完整的报文,那么数据不是无法进行解包的,会直接返回。
- 因为
客户端和服务端都要遵循这种规则
,即自定义协议是一种约定,因此双方都要遵守的,因此不存在数据被污染的情况,即网络中传输的数据都是符合要求的。- 因此客户端传输的数据可以被服务端正确的提取,提取之后,我们要进行解析和处理数据,并将处理后的数据以:【结果 返回码】,
返回码用于检查数据是否计算可靠
,比如1 除 0 无法进行计算,设返回码为1表示除0错误。并以上述同样的方式进行封装,将封装之后的结果,返回给用户进行解析,并处理。
2. 实现框架&&代码
- 实现服务器和封装socket套接字。
- 对请求和响应分别进行序列化和反序列化。
- 对序列化的数据进行封装与解包。
- 服务器对解析的数据进行处理和返回。
- 代码框架:
2.1 封装socket
在之前我们实现代码时,主要目的是为了熟悉系统调用接口,熟练使用之后这里我们可以将Socket进行封装(包含客户端与服务端的常用的接口),方便我们之后进行调用:
#pragma once#include<iostream>
#include<string>#include<cstring>
#include<strings.h>
#include<unistd.h>//网络相关的头文件。
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>//小组件
#include"Log.hpp"using std::string;enum FAIL
{CREAT = 1,SIP_TO_NIP,BIND,LISTEN,ACCEPT,CONNECT,
};
uint16_t defaultport = 8080;
string defaultip = "0.0.0.0";
class Sock
{
public:Sock(uint16_t port = defaultport,string ip = defaultip):_port(port),_ip(ip){}~Sock(){if(_sockfd > 0){close(_sockfd);}}//创建套接字void Socket(){_sockfd = socket(AF_INET,SOCK_STREAM,0);if(_sockfd < 0){lg(CRIT,"socket create fail,reason is\%s,errno is %d",strerror(errno),errno);exit(CREAT);}lg(INFORE,"sockfd is %d,create success!",_sockfd);}//获取套接字int GetSocket(){return _sockfd; }//绑定void Bind(){sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(_port);if(inet_pton(AF_INET,_ip.c_str(),&server.sin_addr) != 1){lg(CRIT,"string_ip to inet_ip fail,reason is %s\,errno is %d",strerror(errno),errno);exit(SIP_TO_NIP);}if(bind(_sockfd,(sockaddr*)&server,sizeof(server)) == -1){lg(CRIT,"bind fail,reason is %s,errno \is %d",strerror(errno),errno);exit(BIND);}lg(INFORE,"bind success!");}//监听void Listen(){if(listen(_sockfd,_backlog) == -1){lg(CRIT,"bind fail,reason is %s,errno is\%d",strerror(errno),errno);exit(LISTEN);}lg(INFORE,"lisen success!");}//接收连接int Accept(sockaddr_in* client,socklen_t* len){int fd = accept(_sockfd,(sockaddr*)client,len);if(fd < 0){lg(CRIT,"accept fail,reason is %s,\errno is %d",strerror(errno),errno);exit(ACCEPT);}uint16_t port = ntohs(client->sin_port);char ip[64] = {0};inet_ntop(AF_INET,&(client->sin_addr),ip,sizeof(ip) - 1);lg(INFORE,"accept success,get a new link,ip is\%s, port is %d",ip,port);return fd;}//连接void Connect(sockaddr_in* server){memset(server,0,sizeof(sockaddr_in));server->sin_family = AF_INET;server->sin_port = htons(_port);if(inet_pton(AF_INET,_ip.c_str(),\&(server->sin_addr)) == -1){lg(WARNNING,"inet_pton fail,reason is %s\,errno is %d",strerror(errno),errno);return;}int res = connect(_sockfd,\(sockaddr*)server,sizeof(sockaddr_in));if(res == -1){lg(CRIT,"connect fail,reason is %s,\errno is %d",strerror(errno),errno);exit(CONNECT);return;}lg(INFORE,"connect success!");}//从指定的套接字文件描述符里面读取数据。string Read(int fd){char buffer[128] = {0};ssize_t n = read(fd,buffer,sizeof(buffer) - 1);if(n < 0){lg(CRIT,"read fail,reason is %s,\errno is %d",strerror(errno),errno);sleep(1);return "";}else if(n == 0){lg(INFORE,"read nothing!");sleep(1);return "";}buffer[n] = '\0';return buffer;}//向指定的套接字文件描述符里面写数据。int Write(int fd,const string& str){ssize_t n = write(fd,str.c_str(),str.size());if(n < 0){lg(CRIT,"write fail,reason is %s,errno \is %d",strerror(errno),errno);sleep(1);return n;}else if(n == 0){lg(INFORE,"write nothing!");sleep(1);return n;}return n; }void Close(int fd){close(fd);}
private:int _sockfd;uint16_t _port;string _ip;int _backlog = 5;//?
};
- 以后我们直接用这个小组件即可,不用再手搓系统调用的接口了。
2.2 客户端与服务端
这里我们使用上面封装的socket接口,实现的服务端与客户端。
- 服务端
#pragma once
#include<iostream>
#include<pthread.h>
#include<functional>
#include"../Tools/Socket.hpp"
#include"../Tools/Log.hpp"
using cal_t = function<string(string&)>;
class TcpServer;struct ThreadData
{ThreadData(int fd,TcpServer* tp):_fd(fd),_tp(tp){}int _fd;TcpServer* _tp;
};
class TcpServer
{
public:TcpServer(uint16_t port = 8080,cal_t cal = nullptr):_socket(port),_cal(cal){}~TcpServer(){}void Init(){_socket.Socket();_socket.Bind();_socket.Listen();}static void* Rouetine(void* args){//分离线程pthread_detach(pthread_self());auto thread_ptr = static_cast<ThreadData*>(args);TcpServer* tp = thread_ptr->_tp;int fd = thread_ptr->_fd;tp->Server(fd);return nullptr;}void Run(){for(;;){sockaddr_in client;socklen_t len = sizeof(client);int fd = _socket.Accept(&client,&len);pthread_t tid;pthread_create(&tid,nullptr,Rouetine,\new ThreadData(fd,this));}}void Server(int fd){string mes;for(;;){sleep(10);//收消息string str = _socket.Read(fd);//啥也没读到if(str == "") break;mes += str;//处理消息string ans;string echo_mes;//一次处理一批while((echo_mes = _cal(mes)) != ""){ans += echo_mes;}//没有读取到整段的报文或者报文为空。int res = _socket.Write(fd,ans);if(res <= 0) break;}_socket.Close(fd);}
private:Sock _socket;cal_t _cal; //这里的cal函数是对接收的消息的处理方法。
};
- 根据上面的信息,我们可以大致了解服务器的基本框架:
- 创建套接字,绑定套接字,监听套接字。
- 接收外面的请求,建立连接,接收信息。
- 调用处理信息的接口,返回处理之后的信息。
- 因此: 我们可以让服务器与处理信息的逻辑进行解耦,并且使用封装之后的套接字是很方便的。
- 客户端:
#pragma once
#include<iostream>
#include<string>#include"../Tools/Log.hpp"
#include"../Tools/protocol.hpp"
#include"../Tools/Socket.hpp"using std::string;
string default_ip = "59.110.171.164";
uint16_t default_port = 8080;
class TcpClient
{
public:TcpClient(string ip = default_ip,uint16_t port = default_port):_sock(port,ip){}void Init(){}void Run(){string res;for(;;){_sock.Socket();sockaddr_in server;_sock.Connect(&server); int fd = _sock.GetSocket();while(true){cout << "Please Enter@";int x,y;char oper;cin >> x >> oper >> y;Request req(x,y,oper);string str = req.Serialize();//为了更好的体现自定义协议,这里我们多次进行写入。_sock.Write(fd,str);_sock.Write(fd,str);_sock.Write(fd,str);_sock.Write(fd,str);_sock.Write(fd,str);sleep(10);//一次读一批res += _sock.Read(fd);Response resq;//一次处理一批:while(resq.Deserialize(res));}_sock.Close(fd);}}
private:Sock _sock;
};
- 说明:这里我们让客户端一次发一批消息,处理一批消息,服务端一次处理一批消息,发一批消息,这样更加能够体现自定义协议的功能。
2.3 封装与解包
//.....char space = ' ';
char newline = '\n';
//解包
string Decode(string& str)
{int pos = str.find(newline);if(pos == string::npos) return "";int len = stoi(str.substr(0,pos));int totalsize = pos + len + 2;//如果总的报文的长度大于读取的字符串的长度,说明没有一个完整的报文。if(totalsize > str.size()){return "";}//将有效载荷截取出来string actual_load = str.substr(pos + 1,len);//将完整的报文丢弃,便于下一次进行读取。str.erase(0,totalsize);return actual_load;
}
//编码
string InCode(const string& str)
{//一个完整的报文:有效载荷的长度 + 换行符 + 有效载荷 + 换行。string text = to_string(str.size()) + newline + str + newline;return text;
}
- 封装数据,我们将在报头处封装有效载荷的长度,并以换行符作为分割符。
- 解析数据,首先要找到有效载荷的长度,并检验是否存在一个完整的报文。
2.4 请求与响应
struct Request
{Request(int x, int y, char oper):_x(x), _y(y), _oper(oper){}Request(){}bool Deserialize(string& str){cout << "+++++++++++++++++++++++++++++" << endl;//首先把字符串的报头和有效载荷进行分离string content = Decode(str);if(content == "") return false;//解析字符串:字符 + 空格 + 字符int left = content.find(space);int right = content.rfind(space);if (left + 1 != right - 1){//说明是无效的字符return false;}_x = stoi(content.substr(0, left));_y = stoi(content.substr(right + 1));_oper = content[left + 1];cout << "解析的字符串:"<< _x << _oper << _y << endl; cout << "待读取的字符串:" << endl << str << endl;cout << "-------------------------------" << endl;return true;}string Serialize(){string package;//首先对结构体进行编码//编码格式:字符 + 空格 + 操作符 + 空格 + 字符package = to_string(_x) + space + _oper + space\+ to_string(_y); //对报文再进行封装package = InCode(package);return package;}int _x = 0;int _y = 0;char _oper = '0';//给出一个缺省值,避免编译器告警。
};struct Response
{Response(int res, int code):_res(res), _code(code){}Response(){}bool Deserialize(string& str){string content = Decode(str);if (content == "") return false;int pos = content.find(space);_res = stoi(content.substr(0,pos));_code = stoi(content.substr(pos + 1));//for debug:cout << "+++++++++++++++++++++++++++++++" << endl;cout <<"转换结果:"<< _res << " " << _code << endl;cout << "待读取的字符串" << endl << str << endl;cout << "-------------------------------" << endl;return true;}string Serialize(){string package = to_string(_res) + space \+ to_string(_code);package = InCode(package);return package;}int _res = 0;int _code = 0;//同理。
};
- Request,是客户端对服务器发送的请求,要客户端进行序列化,服务端进行反序列化,并进行解析。
- Response,是服务端对客户端发送的响应,要服务端进行序列化,客户端进行反序列化,并进行解析。
2.5 对数据进行处理
#include<iostream>
#include"../Tools/Log.hpp"
#include"../Tools/protocol.hpp"enum CAL
{DIV_ZERO = 1,MOD_ZERO,
};
struct CalHelper
{string Cal(string& str){Request req;if(req.Deserialize(str) == false) return "";int x = req._x;int y = req._y;char op = req._oper;int res = 0, code = 0;switch(op){case '+':res = x + y;break;case '-':res = x - y;break;case '*': res = x * y;break;case '/':if(!y){code = DIV_ZERO;break;}res = x / y;break;case '%':if(!y){code = MOD_ZERO;break;}res = x % y;break;default:break;}return Response(res,code).Serialize();}
};
- 这是服务器对客户端请求的处理,包含请求的反序列化和对数据的处理,以及结果的序列化。
2.6 主程序逻辑
- client.cc
#include<iostream>
#include<memory>
#include"clientcal.hpp"
using std::unique_ptr;
void Usage(char* pragma_name)
{cout << endl << "Usage: " << pragma_name << \"+ ip + port[8000-8888]" << endl << endl;
}
int main(int argc,char* argv[])
{if(argc != 3){Usage(argv[0]);return 1;}string ip = argv[1];uint16_t port = stoi(argv[2]);unique_ptr<TcpClient> cp(new TcpClient(ip,port));cp->Init();cp->Run();return 0;
}
- server.cc
#include<iostream>
#include<memory>
#include<functional>
#include"server.hpp"
#include"servercal.hpp"
using std::unique_ptr;void Usage(char* pragma_name)
{cout << endl << "Usage: " << pragma_name \<< " + port[8000-8888]" << endl << endl;
}
int main(int argc,char* argv[])
{if(argc != 2){Usage(argv[0]);return 1;}uint16_t port = stoi(argv[1]);CalHelper cal;unique_ptr<TcpServer> tp(new TcpServer(port,\bind(&CalHelper::Cal,&cal,placeholders::_1)));//bind是C++的一个接口,用于封装函数,便于使用。//因为cal是库里面的,因此要指定作用域,并传this指针,//绑定参数,进而封装出指定类型的函数。tp->Init();tp->Run();return 0;
}
- bind的使用:跳转详见目录
- 运行结果:
- 这里我们传数据,接收数据,处理数据都是一批一批的进行的,因此可以看见待处理的字符串。
3.Json的简单使用
- 在上面实现的过程中,唯一比较难设计的就是序列化与反序列化的过程,上面我们为了进一步的理解,所以自己设计,但是市面上有一些简单好用的序列化与反序列化工具,下面我们介绍一种。
在网络中,序列化与反序列化有现成的工具,比如json 和 protobuf这两个工具,下面我们简单介绍Json的使用。
- 安装Json库
sudo yum install -y jsoncpp-devel
- 说明: 普通用户需要输入root密码并且要添加到系统的信任白名单中,所以这里建议直接su命令切到root用户直接安装。
- 简单使用
- test.cc
#include<iostream>
#include<string>
#include<jsoncpp/json/json.h>
using namespace std;
int main()
{Json::Value root;Json::StyledWriter writer;//Json::FastWriter writer;//StyleWriter打印起来比较有风格。//FastWrier打印比较紧凑,比较省空间。root["x"] = 1;root["y"] = 2;root["oper"] = '+';string res = writer.write(root);//序列化之后的结果:cout << "序列化之后的结果:" << endl;cout << res << endl;Json::Value des;Json::Reader r;r.parse(res,des);int x = des["x"].asInt();int y = des["y"].asInt();char oper = des["oper"].asInt();//反序列化的结果:cout << "反序列化的结果为:" << endl;cout << x << " " << oper << " " << y << endl;return 0;
}
- 编译运行查看结果
g++ test.cc -std=c++11 -ljsoncpp
总结
- 铺垫TCP三次握手,四次挥手的概念,以及理解全双工。
- 实现了自定义协议(封装报头) + 序列化与反序列化的 网络版本的计算器。
- 介绍了Json工具的基本使用。
了解自定义协议之后,我们将在下篇认识现成的应用层协议之Http。
尾序
我是舜华,期待与你的下一次相遇!
相关文章:

【Linux进阶之路】网络 —— “?“ (下)
文章目录 前言一、概念铺垫1.TCP2.全双工 二、网络版本计算器1. 原理简要2. 实现框架&&代码2.1 封装socket2.2 客户端与服务端2.3 封装与解包2.4 请求与响应2.5 对数据进行处理2.6 主程序逻辑 3.Json的简单使用 总结尾序 前言 在上文我们学习使用套接字的相关接口进行了…...

【AIGC】Stable Diffusion的建模思想、训练预测方式快速
在这篇博客中,将会用机器学习入门级描述,来介绍Stable Diffusion的关键原理。目前,网络上的使用教程非常多,本篇中不会介绍如何部署、使用或者微调SD模型。也会尽量精简语言,无公式推导,旨在理解思想。让有…...

JVM(类加载机制)
类加载就是 .class 文件, 从文件(硬盘) 被加载到内存(元数据区)中的过程 类加载的过程 加载: 找 .class 文件的过程, 打开文件, 读文件, 把文件读到内存中 验证: 检查 .class 文件的格式是否正确 .class 是一个二进制文件, 其格式有严格的说明 准备: 给类对象分配内存空间 (先在…...

C++ 实战项目之 Boost 搜索引擎
项目地址:https://gitee.com/Vertas/boost-searcher-project 1. 项目背景 日常生活中我们使用过很多搜索引擎,比如百度,搜狗,360搜索等。我们今天是要实现一个像百度这样的搜索引擎嘛?那是不可能的,因为像…...

部署LVS+Keepalived高可用群集(抢占模式,非抢占模式,延迟模式)
目录 一、LVSKeepalived高可用群集 1、实验环境 2、 主和备keepalived的配置 2.1 yum安装ipvsadm和keepalived工具 2.2 添加ip_vs模块并开启ipvsadm 2.3 修改keepalived的配置文件 2.4 调整proc响应参数,关闭linux内核的重定向参数响应 2.5 将主服务器的kee…...

性别和年龄的视频实时监测项目
注意:本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 ([www.aideeplearning.cn]) 性别和年龄检测 Python 项目 首先介绍性别和年龄检测的高级Python项目中使用的专业术语 什么是计算机视觉? 计算机视觉是使计算机能…...

【Spring面试题】
目录 前言 1.Spring框架中的单例bean是线程安全的吗? 2.什么是AOP? 3.你们项目中有没有使用到AOP? 4.Spring中的事务是如何实现的? 5.Spring中事务失效的场景有哪些? 6.Spring的bean的生命周期。 7.Spring中的循环引用 8.构造方法…...

打车代驾小程序开发 醉酒不用怕一键找代驾
近年来,随着我国私家车市场的不断扩大,驾驶员的安全驾驶意识不断提高,以及交通法规对酒后驾驶的严格把握,代驾市场的潜力也在迸发。代驾小程序开发平台成为了代驾人不可或缺的线上接单平台。那么代驾小程序开发需要实现哪些功能呢…...

蓝桥集训之统计子矩阵
统计子矩阵 核心思想:矩阵前缀和 双指针 用i和j双指针 遍历所有子矩阵的列用s和t双指针 遍历所有子矩阵的行求其子矩阵的和 若>k 将s向下移动 矩阵和必定减小(元素个数减少)直到满足<k 因为列一定 行数即为方案数(从t行往上数到s行 共t-s1个区间[t,t][t-1,t]…...

架构师十项全能 你会几个?
架构设计导论 架构师核心能力 架构设计原则 架构设计模式 架构设计核心维度 架构图绘制 企业架构设计 分布式架构理论 微服务架构设计 响应式架构设计 架构设计评估 单元化架构设计 服务网络架构设计 DDD领域驱动设计 技术选型 服务治理设计 安全架构设计 云架构设计 数据库架构…...

数据库(mysql)-新手笔记(主外键,视图)
主外键 主键(唯一性,非空性) 主键是数据库表中的一个或多个字段,其值唯一标识表中的每一行/记录。 唯一性: 主键字段中的每个值都必须是唯一的,不能有两个或更多的记录具有相同的主键值 非空性:主键字段不能包含NULL值。 外键(引用完整 …...

西门子PLC的交互界面怎样设计?
西门子PLC的交互界面设计集中于提供一个直观、多功能且用户友好的环境,旨在使工程师和技术人员能够有效地进行编程、监控和维护。下面是一些设计西门子PLC交互界面时的关键考虑因素: 1. **图形化编程环境**:设计时,重点在于提供直…...

备份 ChatGPT 的聊天纪录
备份 ChatGPT 的聊天纪录 ChatGPT 在前阵子发生了不少次对话纪录消失的情况,让许多用户觉得困扰不已,也担心自己想留存的聊天记录消失不见。 好消息是,OpenAI 在 2023 年 4 月 11 日推出了 ChatGPT 聊天记录备份功能,无论是免费…...

支持向量机 SVM | 线性可分:软间隔模型
目录 一. 软间隔模型1. 松弛因子的解释小节 2. SVM软间隔模型总结 线性可分SVM中,若想找到分类的超平面,数据必须是线性可分的;但在实际情况中,线性数据集存在少量的异常点,导致SVM无法对数据集线性划分 也就是说&…...

基于Java的生活废品回收系统(Vue.js+SpringBoot)
目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容三、界面展示3.1 登录注册3.2 资源类型&资源品类模块3.3 回收机构模块3.4 资源求购/出售/交易单模块3.5 客服咨询模块 四、免责说明 一、摘要 1.1 项目介绍 生活废品回收系统是可持续发展的解决方案,旨在鼓…...

Linux:好用的Linux指令
进程的Linux指令 1.查看进程信息 ps ajx | head -1 && ps ajx | grep 进程名创建一个进程后输入上述代码,会打印进程信息,当我们在code.exe中写入打印pid,ppid,这里也和进程信息一致。 while :; do ps ajx | he…...

Python Tkinter GUI 基本概念
归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍 收藏⭐ 留言📝如果停止,就是低谷…...

Python实习生(自动化测试脚本开发) - 面经 - TCL新技术有限公司
JD: 招聘流程: 2024.1.3 Boss直聘 沟通 2024.1.4 约面 2024.1.6 上午面试 面试流程: 上来第一步,直接问Python基础语法,讲一下基础的数据类型 就记得元组和字典 分别具体说一下元组和字典 流程控制语句有哪些&…...

遥遥领先!基于transformer变体的时间序列预测新SOTA!
目前,以CNN、RNN和 Transformer 模型为代表的深度学习算法已经超越了传统机器学习算法,成为了时间序列预测领域一个新的研究趋向。这其中,基于Transformer架构的模型在时间序列预测中取得了丰硕的成果。 Transformer模型因其强大的序列建模能…...

Java实现从本地读取CSV文件数据
一、前言 最近项目中需要实现这样一个功能,就是从本地读取CSV文件,并以指定行作为标题行,指定行开始作为数据读取行,读取数据并返回给前端,下面具体说下是如何通过java实现。 二、如何实现? 1.引入相关mav…...

数据结构(一)——概述
一、绪论 1.1数据结构的基本概念 数据:用来描述客观事物的数、计算机中是字符及所有能输入并被程序识别和处理的符号的集合。 数据元素:数据的基本单位,一个数据元素可由若干数据项组成。 数据结构:指相互之间存在一种或多种特…...

昇腾芯片解析:华为自主研发的人工智能处理器全面分析
在当今科技发展的浪潮中,昇腾芯片作为一种新兴的处理器,正引起广泛的关注和讨论。升腾芯片究竟是由哪家公司生产的?这个问题一直困扰着许多人。下面小编将全面介绍、分析升腾芯片的生产商及各类参数、应用,以便读者对其有更全面的…...

新手做抖音小店怎么快速出体验分?教给大家一个方法!
大家好,我是电商糖果 新店怎么出体验分? 这是不是很多新店商家最苦恼事情? 因为没有体验分的店铺,平台不会给推流,开了精选联盟也没有办法带货。 总之就是运营的时候,比较受限。 那么抖音小店怎么快速出…...

Apollo决策规划 - EM planner
旨在对b站老王所讲的百度Apollo - EM planner算法做浓缩版总结 0 决策规划背景 基于图搜索 优点: 可以得到全局层面最优解,适用于比较低维数的规划问题 缺点: 规划问题维数较高时,面临指数爆炸问题 基于采样 优点:…...

Qt: 事件过滤器的更多用法
不懂事件循环怎么回事的可以看下面的文章 Qt事件循环完整流程 常规使用 定义一个窗口MainWindow ,之后在窗口里添加一个事件过滤函数eventFilter,将窗口的某一个或一些字控件安装上事件过滤器。 这种情况下MainWindow 就是pushButton11的时间过滤器&am…...

解决:ModuleNotFoundError: No module named ‘paddle‘
错误显示: 原因: 环境中没有‘paddle’的python模块,但是您在尝试导入 解决方法: 1.普通方式安装: pip install paddlepaddle #安装命令 2.镜像源安装 pip install paddlepaddle -i https://pypi.tuna.tsinghua.e…...

上海雷卯可以解决YPbPr/ YCbCr接口 ESD/EOS静电浪涌问题
YPbPr /YCbCr 接口传输的是视频信号,不传输音频信号。YPbPr 和 YCbCr 都是视频信号的颜色编码格式,多应用于机顶盒(Set-top box),TV电视,投影仪,游戏机和DVD播放器。 YPbPr:是一种模拟视频接口…...

【FPGA/IC】CRC电路的Verilog实现
前言 在通信过程中由于存在各种各样的干扰因素,可能会导致发送的信息与接收的信息不一致,比如发送数据为 1010_1010,传输过程中由于某些干扰,导致接收方接收的数据却成了0110_1010。为了保证数据传输的正确性,工程师们…...

go语言添加代理
LiteIDE 工具->管理 https://mirrors.aliyun.com/goproxy/或https://goproxy.cn,direct 命令行 go env -w GOPROXYhttps://goproxy.cn,direct...

kafka 可视化工具
kafka可视化工具 随着科技发展,中间件也百花齐放。平时我们用的redis,我就会通过redisInsight-v2 来查询数据,mysql就会使用goland-ide插件来查询,都挺方便。但是kafka可视化工具就找了半天,最后还是觉得redpandadata…...