【Linux网络编程】第十弹---打造初级网络计算器:从协议设计到服务实现
✨个人主页: 熬夜学编程的小林
💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】【Linux网络编程】
目录
1、Protocol.hpp
1.1、Request类
1.1.1、基本结构
1.1.2、构造析构函数
1.1.3、序列化函数
1.1.4、反序列化函数
1.1.5、获取成员变量函数
1.1.6、设置成员变量值函数
1.2、Response类
1.2.1、基本结构
1.2.2、构造析构函数
1.2.3、序列化函数
1.2.4、反序列化函数
1.2.5、打印函数
1.3、Factory类
1.4、添加报头
1.5、解析报头
2、Service.hpp
2.1、构造析构函数
2.2、IOExcute()
2.3、Recv()
3、NetCal.hpp
3.1、构造析构函数
3.2、Calculator()
4、ClientMain.cc
5、完整代码
5.1、Protocol.hpp
5.2、Service.hpp
5.3、ClientMain.cc
5.4、Makefile
上一弹已经写好服务端代码,并讲解了序列化使用到的json库,这弹开始写协议,并完成网络计算器的代码!

1、Protocol.hpp
该文件实现序列化与反序列使用到的类和相关函数(加报头解报头)!
1.1、Request类
该类是向服务器发送请求的类,需要三个成员变量,_x,_y,_oper(运算符号),统一的计算格式是 _x _oper _y,内部主要是序列化(发送)和反序列化(接受)函数!
1.1.1、基本结构
该类有三个成员变量,_x,_y,_oper(运算符号),序列化,反序列化,构造,析构及其他获取成员变量与打印的函数!
class Request
{
public:Request(){}// 序列化 将结构化转成字符串bool Serialize(std::string *out);// 反序列化 将字符串转成结构化bool Deserialize(const std::string &in);void Print();~Request();int X();int Y();char Oper();
private:int _x;int _y;char _oper; // + - * / % // x oper y
};
1.1.2、构造析构函数
为了方便后面的使用,此处实现两个构造函数,一个无参,一个带参函数,析构函数无需处理!
Request()
{}
Request(int x,int y,char oper):_x(x),_y(y),_oper(oper)
{}~Request()
{}
1.1.3、序列化函数
序列化即将结构化转成字符串,并将字符串以输出型参数传出!
// 序列化 将结构化转成字符串
bool Serialize(std::string *out)
{// 1.自己做: "x oper y" (麻烦)// 2.使用现成的库, xml,json(jsoncpp库), protobufJson::Value root;root["x"] = _x;root["y"] = _y;root["oper"] = _oper;Json::FastWriter writer;std::string s = writer.write(root);*out = s;return true;
}

1.1.4、反序列化函数
反序列化即将字符串转成结构化,参数传入字符串!
// 反序列化 将字符串转成结构化
bool Deserialize(const std::string &in)
{Json::Value root;Json::Reader reader;bool res = reader.parse(in,root);_x = root["x"].asInt();_y = root["y"].asInt();_oper = root["oper"].asInt();return true;
}
打印函数
void Print()
{std::cout << _x << std::endl;std::cout << _y << std::endl;std::cout << _oper << std::endl;
}

1.1.5、获取成员变量函数
因为成员变量是私有的,外部访问使用成员函数!
int X()
{return _x;
}
int Y()
{return _y;
}
char Oper()
{return _oper;
}
1.1.6、设置成员变量值函数
void SetValue(int x, int y, char oper)
{_x = x;_y = y;_oper = oper;
}
1.2、Response类
该类是向客户端发送结果的类,需要三个成员变量,_result(计算结果),_code(自定义错误码[0: success 1: div error 2: 非法操作]),_desc(错误码描述),内部主要是序列化(发送)和反序列化(接受)函数!
1.2.1、基本结构
该类有三个成员变量,_result(计算结果),_code(自定义错误码),_desc(错误码描述),序列化,反序列化,构造,析构和打印函数!
注意:为了方便类外访问该类成员变量,该成员变量是公有的!
class Response
{
public:Response();// 序列化 将结构化转成字符串bool Serialize(std::string *out);// 反序列化 将字符串转成结构化bool Deserialize(const std::string &in);~Response();
public:int _result;int _code; // 0: success 1: div error 2: 非法操作std::string _desc;
};
1.2.2、构造析构函数
构造函数直接手动初始化(结果和错误码初始化为0,描述默认初始化为success),析构函数无需处理!
Response():_result(0),_code(0),_desc("success")
{}~Response()
{}
1.2.3、序列化函数
序列化即将结构化转成字符串,并将字符串以输出型参数传出!
// 序列化 将结构化转成字符串
bool Serialize(std::string *out)
{// 使用现成的库, xml,json(jsoncpp库), protobufJson::Value root;root["result"] = _result;root["code"] = _code;root["desc"] = _desc;Json::FastWriter writer;std::string s = writer.write(root);*out = s;return true;
}
1.2.4、反序列化函数
反序列化即将字符串转成结构化,参数传入字符串!
// 反序列化 将字符串转成结构化
bool Deserialize(const std::string &in)
{Json::Value root;Json::Reader reader;bool res = reader.parse(in,root);_x = root["x"].asInt();_y = root["y"].asInt();_oper = root["oper"].asInt();return true;
}
1.2.5、打印函数
将成员变量以字符串形式打印出来即可!
void PrintResult()
{std::cout << "result: " << _result << ", code: " << _code << ", desc: " << _desc << std::endl;
}
1.3、Factory类
因为Request类和Response类可能频繁创建,因此我们可以设计一个工厂类,内部设计两个创建类的静态函数(没有this指针,外部直接调用函数即可)!
class Factory
{
public:static std::shared_ptr<Request> BuildRequestDefault(){return std::make_shared<Request>();}static std::shared_ptr<Response> BuildResponseDefault(){return std::make_shared<Response>();}
};
1.4、添加报头
在实际的网络通信中,传的不仅仅是序列化之后的字符串,还会有报头信息,此处我们也设计一下报头信息,格式如下:
1、"len"\r\n"{json}"\r\n --- 完整的报文
2、len 有效载荷的长度
3、\r\n(第一个): 区分len 和 json 串
4、\r\n(第二个): 暂时没有其他用,打印方便,debug
static const std::string sep = "\r\n"; // 分隔符// 添加报头
std::string Encode(const std::string &jsonstr)
{int len = jsonstr.size();std::string lenstr = std::to_string(len);return lenstr + sep + jsonstr + sep;
}
1.5、解析报头
将发送过来的有报头的信息解析成有效信息,即去掉前面的长度和分割符与有效信息后面的分隔符!
注意:可能没有一个有效信息或者有多个有效信息!
static const std::string sep = "\r\n"; // 分隔符// 不能带const
// "le
// "len"\r\n"{j [)
// "len"\r\n"{json}"\r\n"
// "len"\r\n"{json}"\r\n"len"\r\n
// "len"\r\n"{json}"\r\n"len"\r\n"{json}"\r\n"
// "len"\r\n"{json}"\r\n"len"\r\n"{json}"\r\n"len"\r\n"{json}"\r\n"std::string Decode(std::string &packagestream)
{// 分析auto pos = packagestream.find(sep); // 报文流if (pos == std::string::npos)return std::string(); // 没找到返回空std::string lenstr = packagestream.substr(0, pos);int len = std::stoi(lenstr); // json长度// 计算一个完整的报文应该是多长int total = lenstr.size() + len + 2 * sep.size();// 传进来的字符串长度小于报文总长,说明没有一个完整的有效信息,返回空if (packagestream.size() < total)return std::string();// 提取std::string jsonstr = packagestream.substr(pos + sep.size(), len);packagestream.erase(0, total); // 从0位置删除total长度return jsonstr;
}
2、Service.hpp
Service.hpp中的 IOService类 是用于通信的类,而且内部需要执行传入的回调函数,因此该类需要加一个执行方法的成员!
执行方法的声明:
参数是请求类的指针,返回值是应答类的指针!
using process_t = std::function<std::shared_ptr<Response>(std::shared_ptr<Request>)>;
2.1、构造析构函数
构造函数需要传入函数对象,用于初始化成员变量,析构函数无需处理!
IOService(process_t process) :_process(process)
{}~IOService()
{}
2.2、IOExcute()
IOExcute()函数进行客户端与服务端的通信,并处理发送过来的信息(调用执行方法),有以下7个主要步骤!
1、接收消息
2、报文解析(保证获取至少获得一条有效信息,没有则继续接受消息)
3、反序列化(将字符串转成结构化)
4、业务处理(调用构造函数传入的回调函数)
5、序列化应答
6、添加len长度(报头)
7、发送回去
void IOExcute(SockSPtr sock, InetAddr &addr)
{std::string packagestreamqueue; // 写在while循环外,存储信息while (true){// 1.负责读取ssize_t n = sock->Recv(&packagestreamqueue);if(n <= 0){LOG(INFO, "client %s quit or recv error\n", addr.AddrStr().c_str());break;}std::cout << "--------------------------------------------" << std::endl;std::cout << "packagestreamqueue: \n" << packagestreamqueue << std::endl;// 我们能保证读到的是完整的报文? 不能!// 2.报文解析,提取报头和有效载荷std::string package = Decode(packagestreamqueue);if(package.empty()) continue;// 我们能保证读到的是一个完整的报文!!!auto req = Factory::BuildRequestDefault();std::cout << "package: \n" << package << std::endl;// 3.反序列化req->Deserialize(package); // 反序列化 将字符串转成结构化// 4.业务处理auto resp = _process(req); // 业务处理(通过请求,得到应答)// 5.序列化应答std::string respjson;resp->Serialize(&respjson); // 序列化std::cout << "respjson: \n" << respjson << std::endl;// 6.添加len长度respjson = Encode(respjson);std::cout << "respjson add header done: \n" << respjson << std::endl;// 7.发送回去sock->Send(respjson);}
此处有一个问题,如果第一次接收消息没有读到完整的报文就会继续接受消息,但是以我们前面写的接收消息函数会清空内容,因此我们需要做稍微的修改!
2.3、Recv()
Recv()函数是Socket.hpp文件中TcpServer类的成员函数,接收消息成功之后需要该为拼接旧的内容!
// 接收消息
ssize_t Recv(std::string *out) override
{char inbuffer[4096];ssize_t n = ::recv(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0);if (n > 0){inbuffer[n] = 0;// *out = inbuffer;*out += inbuffer; // 调整(可能一次读取不成功 | 读取多次)}return n;
}
3、NetCal.hpp
NetCal.hpp文件中的NetCal类包含回调函数的具体实现!
3.1、构造析构函数
该类没有成员变量,构造析构函数无需处理!
NetCal()
{}~NetCal()
{}
3.2、Calculator()
Calculator() 函数用于网络计算器的计算逻辑!
std::shared_ptr<Response> Calculator(std::shared_ptr<Request> req)
{auto resp = Factory::BuildResponseDefault();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;resp->_desc = "divc zero";}else{resp->_result = req->X() / req->Y();}}break;case '%':{if(req->Y() == 0){resp->_code = 2;resp->_desc = "mod zero";}else{resp->_result = req->X() % req->Y();}}break;default:{resp->_code = 3;resp->_desc = "illegal operation";}break;}return resp;
}
4、ClientMain.cc
该文件用户创建TcpServer类对象,并调用执行函数运行客户端!
通信操作主要包括以下七步:
1、序列化
2、添加长度报头字段
3、发送数据
4、读取应答,response
5、报文解析,提取报头和有效载荷
6、反序列化
7、打印结果
#include <iostream>
#include <ctime>
#include "Socket.hpp"
#include "Protocol.hpp"using namespace socket_ns;int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "Usage: " << argv[0] << " server-ip server-port" << std::endl;exit(0);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);SockSPtr sock = std::make_shared<TcpSocket>();if (!sock->BuildClientSocket(serverip, serverport)){std::cerr << "connect error" << std::endl;exit(1);}srand(time(nullptr) ^ getpid());const std::string opers = "+-*/%&^!";std::string packagestreamqueue;while (true){// 构建数据int x = rand() % 10;usleep(x * 1000);int y = rand() % 10;usleep(x * y * 100);char oper = opers[y % opers.size()];// 构建请求auto req = Factory::BuildRequestDefault();req->SetValue(x, y, oper);// 1.序列化std::string reqstr;req->Serialize(&reqstr);// 2.添加长度报头字段reqstr = Encode(reqstr);std::cout << "####################################" << std::endl;std::cout << "requset string: \n" << reqstr << std::endl;// 3.发送数据sock->Send(reqstr);while (true){// 4.读取应答,responsessize_t n = sock->Recv(&packagestreamqueue);if (n <= 0){break;}// 我们能保证读到的是完整的报文? 不能!// 5.报文解析,提取报头和有效载荷std::string package = Decode(packagestreamqueue);if (package.empty())continue;std::cout << "package: \n" << package << std::endl;// 6.反序列化auto resp = Factory::BuildResponseDefault();resp->Deserialize(package);// 7.打印结果resp->PrintResult();break;}sleep(1);}sock->Close();return 0;
}

5、完整代码
5.1、Protocol.hpp
#pragma once
#include <iostream>
#include <memory>
#include <string>
#include <jsoncpp/json/json.h>static const std::string sep = "\r\n"; // 分隔符// 设计一下协议的报头和报文的完整格式
// "len"\r\n"{json}"\r\n --- 完整的报文
// len 有效载荷的长度
// \r\n(第一个): 区分len 和 json 串
// \r\n(第二个): 暂时没有其他用,打印方便,debug// 添加报头
std::string Encode(const std::string &jsonstr)
{int len = jsonstr.size();std::string lenstr = std::to_string(len);return lenstr + sep + jsonstr + sep;
}// 不能带const
// "le
// "len"\r\n"{j [)
// "len"\r\n"{json}"\r\n"
// "len"\r\n"{json}"\r\n"len"\r\n
// "len"\r\n"{json}"\r\n"len"\r\n"{json}"\r\n"
// "len"\r\n"{json}"\r\n"len"\r\n"{json}"\r\n"len"\r\n"{json}"\r\n"std::string Decode(std::string &packagestream)
{// 分析auto pos = packagestream.find(sep); // 报文流if (pos == std::string::npos)return std::string(); // 没找到返回空std::string lenstr = packagestream.substr(0, pos);int len = std::stoi(lenstr); // json长度// 计算一个完整的报文应该是多长int total = lenstr.size() + len + 2 * sep.size();// 传进来的字符串长度小于报文总长,说明没有一个完整的有效信息,返回空if (packagestream.size() < total)return std::string();// 提取std::string jsonstr = packagestream.substr(pos + sep.size(), len);packagestream.erase(0, total); // 从0位置删除total长度return jsonstr;
}// 协议
class Request
{
public:Request(){}Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper){}// 序列化 将结构化转成字符串bool Serialize(std::string *out){// 1.自己做: "x oper y" (麻烦)// 2.使用现成的库, xml,json(jsoncpp库), protobufJson::Value root;root["x"] = _x;root["y"] = _y;root["oper"] = _oper;Json::FastWriter writer;std::string s = writer.write(root);*out = s;return true;}// 反序列化 将字符串转成结构化bool Deserialize(const std::string &in){Json::Value root;Json::Reader reader;bool res = reader.parse(in, root);_x = root["x"].asInt();_y = root["y"].asInt();_oper = root["oper"].asInt();return true;}void Print(){std::cout << _x << std::endl;std::cout << _y << std::endl;std::cout << _oper << std::endl;}~Request(){}int X(){return _x;}int Y(){return _y;}char Oper(){return _oper;}void SetValue(int x, int y, char oper){_x = x;_y = y;_oper = oper;}private:int _x;int _y;char _oper; // + - * / % // x oper y
};// class request resp = {30,0}
class Response
{
public:Response() : _result(0), _code(0), _desc("success"){}// 序列化 将结构化转成字符串bool Serialize(std::string *out){// 使用现成的库, xml,json(jsoncpp库), protobufJson::Value root;root["result"] = _result;root["code"] = _code;root["desc"] = _desc;Json::FastWriter writer;std::string s = writer.write(root);*out = s;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();_desc = root["desc"].asString();return true;}void PrintResult(){std::cout << "result: " << _result << ", code: " << _code << ", desc: " << _desc << std::endl;}~Response(){}public:int _result;int _code; // 0: success 1: div error 2: 非法操作std::string _desc;
};class Factory
{
public:static std::shared_ptr<Request> BuildRequestDefault(){return std::make_shared<Request>();}static std::shared_ptr<Response> BuildResponseDefault(){return std::make_shared<Response>();}
};
5.2、Service.hpp
#pragma once
#include <iostream>
#include <functional>
#include "InetAddr.hpp"
#include "Socket.hpp"
#include "Log.hpp"
#include "Protocol.hpp"using namespace socket_ns;
using namespace log_ns;using process_t = std::function<std::shared_ptr<Response>(std::shared_ptr<Request>)>;class IOService
{
public:IOService(process_t process) :_process(process){}void IOExcute(SockSPtr sock, InetAddr &addr){std::string packagestreamqueue; // 写在while循环外,存储信息while (true){// 1.负责读取ssize_t n = sock->Recv(&packagestreamqueue);if(n <= 0){LOG(INFO, "client %s quit or recv error\n", addr.AddrStr().c_str());break;}std::cout << "--------------------------------------------" << std::endl;std::cout << "packagestreamqueue: \n" << packagestreamqueue << std::endl;// 我们能保证读到的是完整的报文? 不能!// 2.报文解析,提取报头和有效载荷std::string package = Decode(packagestreamqueue);if(package.empty()) continue;// 我们能保证读到的是一个完整的报文!!!auto req = Factory::BuildRequestDefault();std::cout << "package: \n" << package << std::endl;// 3.反序列化req->Deserialize(package); // 反序列化 将字符串转成结构化// 4.业务处理auto resp = _process(req); // 业务处理(通过请求,得到应答)// 5.序列化应答std::string respjson;resp->Serialize(&respjson); // 序列化std::cout << "respjson: \n" << respjson << std::endl;// 6.添加len长度respjson = Encode(respjson);std::cout << "respjson add header done: \n" << respjson << std::endl;// 7.发送回去sock->Send(respjson);}}// 测试// void IOExcute(SockSPtr sock, InetAddr &addr)// {// while (true)// {// std::string message;// ssize_t n = sock->Recv(&message);// if(n > 0)// {// LOG(INFO, "get message from client [%s],message: %s\n", addr.AddrStr().c_str(), message.c_str());// std::string hello = "hello";// sock->Send(hello);// }// else if(n == 0)// {// LOG(INFO, "client %s quit\n", addr.AddrStr().c_str());// break;// }// else // {// LOG(ERROR, "read error\n", addr.AddrStr().c_str());// break;// }// }// }~IOService(){}
private:process_t _process;
};
5.3、ClientMain.cc
#include <iostream>
#include <ctime>
#include "Socket.hpp"
#include "Protocol.hpp"using namespace socket_ns;int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "Usage: " << argv[0] << " server-ip server-port" << std::endl;exit(0);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);SockSPtr sock = std::make_shared<TcpSocket>();if (!sock->BuildClientSocket(serverip, serverport)){std::cerr << "connect error" << std::endl;exit(1);}srand(time(nullptr) ^ getpid());const std::string opers = "+-*/%&^!";std::string packagestreamqueue;while (true){// 构建数据int x = rand() % 10;usleep(x * 1000);int y = rand() % 10;usleep(x * y * 100);char oper = opers[y % opers.size()];// 构建请求auto req = Factory::BuildRequestDefault();req->SetValue(x, y, oper);// 1.序列化std::string reqstr;req->Serialize(&reqstr);// 2.添加长度报头字段reqstr = Encode(reqstr);std::cout << "####################################" << std::endl;std::cout << "requset string: \n" << reqstr << std::endl;// 3.发送数据sock->Send(reqstr);while (true){// 4.读取应答,responsessize_t n = sock->Recv(&packagestreamqueue);if (n <= 0){break;}// 我们能保证读到的是完整的报文? 不能!// 5.报文解析,提取报头和有效载荷std::string package = Decode(packagestreamqueue);if (package.empty())continue;std::cout << "package: \n" << package << std::endl;// 6.反序列化auto resp = Factory::BuildResponseDefault();resp->Deserialize(package);// 7.打印结果resp->PrintResult();break;}sleep(1);}sock->Close();return 0;
}
5.4、Makefile
.PHONY:all
all:calserver calclientcalserver:ServerMain.cc g++ -o $@ $^ -std=c++14 -ljsoncppcalclient:ClientMain.cc g++ -o $@ $^ -std=c++14 -ljsoncpp.PHONY:clean
clean:rm -rf calserver calclient
相关文章:
【Linux网络编程】第十弹---打造初级网络计算器:从协议设计到服务实现
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【Linux网络编程】 目录 1、Protocol.hpp 1.1、Request类 1.1.1、基本结构 1.1.2、构造析构函数 1.1.3、序列化函数 1.1.4、反…...
无限弹窗?无限重启?
Windows开机自启目录: "%USERPROFILE%\AppData\Roaming\Microsoft\windows\StartMenu\Programs\Startup" 基于这个和 start 命令, shutdown 命令, 编写 bat 病毒程序。 无限弹窗 echo start cmd > hack.txt echo %0 >>…...
深入详解人工智能机器学习常见算法中的K-means聚类
目录 引言 1. K-means聚类的基本概念 1.1 K-means聚类的定义 1.2 K-means聚类的核心思想 1.3 K-means聚类的目标函数 2. K-means聚类的核心原理 2.1 初始化 2.2 分配 2.3 更新 2.4 迭代 3. K-means聚类的具体实现 3.1 K-means聚类的算法流程 3.2 K-means聚类的Pyt…...
lc146LRU缓存——模仿LinkedHashMap
146. LRU 缓存 - 力扣(LeetCode) 法1: 调用java现有的LinkedHashMap的方法,但不太理解反正都不需要扩容,super(capacity, 1F, true);不行吗,干嘛还弄个装载因子0.75还中途扩容一次浪费时间。 class LRUC…...
全面深入解析:C语言动态库
引言 动态库(Dynamic Library)是现代软件开发中不可或缺的一部分,它们不仅提高了代码的重用性和维护性,还显著提升了系统的性能和资源利用率。本文将全面探讨C语言中的动态库,从基础概念到高级应用,通过丰…...
运用 SSM 实现垃圾分类系统智能化升级
目 录 摘 要 1 前 言 3 第1章 概述 4 1.1 研究背景 4 1.2 研究目的 4 1.3 研究内容 4 第二章 开发技术介绍 5 2.1Java技术 6 2.2 Mysql数据库 6 2.3 B/S结构 7 2.4 SSM框架 8 第三章 系统分析 9 3.1 可行性分析 9 3.1.1 技术可行性 9 3.1.2 经济可行性 10 3.1.3 操作可行性 10 …...
LeNet-5:深度学习与卷积神经网络的里程碑
目录 编辑 引言 LeNet-5的结构与原理 输入层 C1层:卷积层 S2层:池化层 C3层:卷积层 S4层:池化层 C5层:卷积层 F6层:全连接层 输出层 LeNet-5的算法基础 LeNet-5的优点 LeNet-5的现代应用 …...
从资产流动分析WIF市场潜力X.game深究其他未知因素
近日,两则关于WIF最新消息引起了投资者们的注意。据报道,11月28日Vintermute在过去13小时内累计从Binance交易所提取了价值533万美元的WIF,此举不仅彰显了其强大的资金实力,更在某种程度上推动了WIF币价的反弹;另一方面…...
深入解析Vue3响应式系统:从Proxy实现到依赖收集的核心原理
深入解析Vue3响应式系统:从Proxy实现到依赖收集的核心原理 响应式系统的基本原理 作为一个热门的JavaScript框架,Vue在3.x版本中引入了基于Proxy的响应式系统。这个系统的核心思想是利用Proxy对象拦截对数据的访问和修改,从而实现数据的自动更…...
FPGA实现GTP光口数据回环传输,基于Aurora 8b/10b编解码架构,提供2套工程源码和技术支持
目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的 GT 高速接口解决方案 3、工程详细设计方案工程设计原理框图用户数据发送模块基于GTP高速接口的数据回环传输架构GTP IP 简介GTP 基本结构GTP 发送和接收…...
Linux网络 UDP socket
背景知识 我们知道, IP 地址用来标识互联网中唯一的一台主机, port 用来标识该主机上唯一的一个网络进程,IPPort 就能表示互联网中唯一的一个进程。所以通信的时候,本质是两个互联网进程代表人来进行通信,{srcIp&…...
如何持续优化呼叫中心大模型呼入机器人的性能?
如何持续优化呼叫中心大模型呼入机器人的性能? 原作者:开源呼叫中心FreeIPCC,其Github:https://github.com/lihaiya/freeipcc 持续优化呼叫中心大模型呼入机器人的性能是一个复杂而细致的过程,它涉及到数据、模型结构…...
鸿蒙项目云捐助第四讲鸿蒙App应用的登陆注册页实现
根据app的操作流程可以知道,当启动页启动后,点击启动页中的页面就进入到了登录页。本讲就是针对于登录注册页的实现,实现的界面参考下图。 这里根据这个素材的参考实现鸿蒙Next云捐助的登录页。 一、鸿蒙Next云捐助登录页的实现 在项目中继…...
Windows本地搭建Redis集群(集群模式)
手打不易,如果转摘,请注明出处! 注明原文:https://blog.csdn.net/q258523454/article/details/144477957 前言 Redis版本:redis 5.0.14.1 Windows版本:Windows10 本文只讲集群模式 1. 安装Redis 1.1 …...
使用FastGPT制做一个AI网站日志分析器
越来越的多网站面临每天上千次的扫描和各类攻击,及时发现攻击IP,并有效的屏蔽不良访问成为网站安全的重要保障,这里我们使用AI来完成对网站日志的日常分析。 我们来使用FastGPT来制做一个AI网站日志析器,下面就开始: …...
探索 Echarts 绘图:数据可视化的奇妙之旅
目录 一、Echarts 初印象 二、搭建 Echarts 绘图环境 三、绘制第一个图表:柱状图的诞生 四、图表的美化与定制:让数据更具吸引力 1. 主题切换:一键变换风格 2. 颜色调整:色彩搭配的艺术 3. 标签与提示框:丰富信…...
网络基础(IP和端口)
网络连接的核心-TCP/IP体系结构(IP和端口) 什么是IP地址 1.IP地址是电子设备(计算机)在互联网上的唯一标识 2.用来在互联网中寻找电脑 IP 地址就像是你家的地址一样,不过它是在网络世界里用来找到一台电脑或者其他网…...
UE4与WEB-UI通信
前端HTML代码 <!DOCTYPE html><html><head><meta charset"utf-8"><meta name"viewport" content"widthdevice-width, initial-scale1"><title>test web ui</title><script src"https://cdn.b…...
前缀和与差分算法详解
定义 前缀和是一种数据预处理技术,它指的是从数组的第一个元素开始,到当前元素为止的所有元素的和。这种技术可以快速计算任意区间内元素的和,而不需要每次都从头开始累加。 差分则是前缀和的逆运算,它主要用于处理对数组某个区…...
《深入探究:C++ 在多方面对 C 语言实现的优化》
目录 一、C 在 C 上进行的优化二、C 关键字(C 98)三、C 的输入输出1. cin 和 cout 的使用2. cin、cout 和 scanf()、printf() 的区别 三、命名空间1. 命名空间的使用2. 嵌套命名空间3. 在多个头文件中使用相同的命名空间 四、函数缺省值1. 缺省值的使用2…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
