RpcRrovider分发rpc服务(OnMessage和Closure回调)
目录
1.完善rpcprovider.cc的OnConnection
2.完善rpcprovider.cc的OnMessage
3.完整rpcprovider.h
4.完整rpcprovider.cc
这篇文章主要完成,protobuf实现的数据序列化和反序列化。
1.完善rpcprovider.cc的OnConnection
rpc的请求是短连接的,请求一次完了,服务端返回rpc的方法的响应,就主动关闭连接了。
//新的socket连接回调
void RpcProvider::OnConnection(const muduo::net::TcpConnectionPtr& conn)
{if(!conn->connected()){//和rpc client的连接断开了conn->shutdown();}
}
2.完善rpcprovider.cc的OnMessage
在框架内部,RpcProvider和RpcConsumer协商好之间通信用的protobuf数据类型
怎么商量呢?
包含:service_name method_name args
对应:16UserService Login zhang san123456
我们在框架中定义proto的message类型,进行数据头的序列化和反序列化
service_name method_name args_size(防止粘包的问题)
怎么去区分哪个是service_name, method_name, args
我们把消息头表示出来
header_size(4个字节) + header_str + args_str
前面几个字节是服务名和方法名。
为了防止粘包,我们还要记录参数的字符串的长度
我们统一:一开始读4个字节,数据头的长度,也就是除了方法参数之外的所有数据:服务名字和方法名字
10 “10”
10000 “1000000”
我们要用到std::string insert和copy方法
把header_size按照内存的方式二进制的形式直接存4个字节。
所以,我们从字符流解析是按:数据头(4字节大小,表示service_name method_name args_size的长度)+service_name method_name args_size(防止粘包的问题)+args(参数)
我们在src里面创建rpcheader.proto文件
syntax = "proto3";package mprpc;message RpcHeader
{bytes service_name=1;bytes method_name=2;uint32 args_size=3;
}
我们打开终端,进入到src下,执行命令。


新增mprpcprovider.cc的OnMessage内容
/*
在框架内部,RpcProvider和RpcConsumer协商好之间通信用的protobuf数据类型
service_name method_name args 定义proto的message类型,进行数据头的序列化和反序列化service_name method_name args_size
16UserServiceLoginzhang san123456header_size(4个字节)+header_str+args_str
10 "10"
10000 "10000"
std::string insert和copy方法
*/
// 已建立连接用户的读写事件回调 如果远程有一个rpc服务的调用请求,那么OnMessage方法就会响应
void RpcProvider::OnMessage(const muduo::net::TcpConnectionPtr& conn,muduo::net::Buffer* buffer,muduo::Timestamp)
{//网络上接收的远程rpc调用请求的字符流 Login argsstd::string recv_buf=buffer->retrieveAllAsString();//从字符流中读取前4个字节的内容uint32_t header_size = 0;recv_buf.copy((char*)&header_size,4,0);//根据header_size读取数据头的原始字符流,反序列化数据,得到rpc请求的详细消息std::string rpc_header_str=recv_buf.substr(4,header_size);mprpc::RpcHeader rpcHeader;std::string service_name;std::string method_name;uint32_t args_size;if(rpcHeader.ParseFromString(rpc_header_str)){//数据头反序列化成功service_name=rpcHeader.service_name();method_name=rpcHeader.method_name();args_size=rpcHeader.args_size();}else{//数据头反序列化失败std::cout<<"rpc_header_str:"<<rpc_header_str<<" parse error!"<<std::endl;return;}//获取rpc方法参数的字符流数据std::string args_str=recv_buf.substr(4+header_size,args_size);//打印调试信息std::cout<<"===================================================="<<std::endl;std::cout<<"header_size:"<<header_size<<std::endl;std::cout<<"rpc_header_str:"<<rpc_header_str<<std::endl;std::cout<<"service_name:"<<service_name<<std::endl;std::cout<<"method_name:"<<method_name<<std::endl;std::cout<<"args_str:"<<args_str<<std::endl;std::cout<<"===================================================="<<std::endl;
}
目前mprpcprovider.cc的完整代码如下:
#include "rpcprovider.h"
#include "mprpcapplication.h"
#include "rpcheader.pb.h"/*
service_name=> service描述(一个服务由一个服务名字对应)=》 service* 记录服务对象method_name => method方法对象
json:存储键值对,基于文本存储;数据有对应的键值
protobuf:基于二进制存储,存储效率更高;紧密存储,不携带除数据外的任何信息,整体来说protobuf存储效率更高,占用的带宽更少,同样带宽传输的数据量更大不仅可以提供类型的序列化和反序列化,还提供了service rpc方法的描述
*/
//这里是框架提供给外部使用的,可以发布rpc方法的函数接口
void RpcProvider::NotifyService(google::protobuf::Service *service)
{ServiceInfo service_info;//获取了服务对象的描述信息const google::protobuf::ServiceDescriptor* pserviceDesc=service->GetDescriptor();//获取服务的名字std::string service_name=pserviceDesc->name();//获取服务对象service的方法的数量int methodCnt=pserviceDesc->method_count();std::cout<<"service_name:"<<service_name<<std::endl;for(int i=0;i<methodCnt;++i){//获取了服务对象指定下标的服务方法的描述(抽象描述) UserService Loginconst google::protobuf::MethodDescriptor* pmethodDesc=pserviceDesc->method(i);std::string method_name=pmethodDesc->name();service_info.m_methodMap.insert({method_name,pmethodDesc});std::cout<<"method_name:"<<method_name<<std::endl;}service_info.m_service=service;m_serviceMap.insert({service_name,service_info});}// 启动rpc服务节点,开始提供rpc远程网络调用服务
void RpcProvider::Run()
{std::string ip=MprpcApplication::GetInstance().GetConfig().Load("rpcserverip");uint16_t port=atoi(MprpcApplication::GetInstance().GetConfig().Load("rpcserverport").c_str());muduo::net::InetAddress address(ip,port);//创建TcpServer对象muduo::net::TcpServer server(&m_eventLoop,address,"RpcProvider");//绑定连接回调和消息读写回调方法 ,muduo库的好处是:分离了网络代码和业务代码server.setConnectionCallback(std::bind(&RpcProvider::OnConnection, this, std::placeholders::_1));//预留1个参数std::placeholders::_1server.setMessageCallback(std::bind(&RpcProvider::OnMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));//预留3个参数std::placeholders::_1,2,3//设置muduo库的线程数量server.setThreadNum(4);std::cout<<"RpcProvider start service at ip:"<<ip<<"port:"<<port<<std::endl;//启动网络服务server.start();m_eventLoop.loop();
}//新的socket连接回调
void RpcProvider::OnConnection(const muduo::net::TcpConnectionPtr& conn)
{if(!conn->connected()){//和rpc client的连接断开了conn->shutdown();}
}
/*
在框架内部,RpcProvider和RpcConsumer协商好之间通信用的protobuf数据类型
service_name method_name args 定义proto的message类型,进行数据头的序列化和反序列化service_name method_name args_size
16UserServiceLoginzhang san123456header_size(4个字节)+header_str+args_str
10 "10"
10000 "10000"
std::string insert和copy方法
*/
// 已建立连接用户的读写事件回调 如果远程有一个rpc服务的调用请求,那么OnMessage方法就会响应
void RpcProvider::OnMessage(const muduo::net::TcpConnectionPtr& conn,muduo::net::Buffer* buffer,muduo::Timestamp)
{//网络上接收的远程rpc调用请求的字符流 Login argsstd::string recv_buf=buffer->retrieveAllAsString();//从字符流中读取前4个字节的内容uint32_t header_size = 0;recv_buf.copy((char*)&header_size,4,0);//根据header_size读取数据头的原始字符流,反序列化数据,得到rpc请求的详细消息std::string rpc_header_str=recv_buf.substr(4,header_size);mprpc::RpcHeader rpcHeader;std::string service_name;std::string method_name;uint32_t args_size;if(rpcHeader.ParseFromString(rpc_header_str)){//数据头反序列化成功service_name=rpcHeader.service_name();method_name=rpcHeader.method_name();args_size=rpcHeader.args_size();}else{//数据头反序列化失败std::cout<<"rpc_header_str:"<<rpc_header_str<<" parse error!"<<std::endl;return;}//获取rpc方法参数的字符流数据std::string args_str=recv_buf.substr(4+header_size,args_size);//打印调试信息std::cout<<"===================================================="<<std::endl;std::cout<<"header_size:"<<header_size<<std::endl;std::cout<<"rpc_header_str:"<<rpc_header_str<<std::endl;std::cout<<"service_name:"<<service_name<<std::endl;std::cout<<"method_name:"<<method_name<<std::endl;std::cout<<"args_str:"<<args_str<<std::endl;std::cout<<"===================================================="<<std::endl;
}
编译
3.完整rpcprovider.h
#pragma once
#include "google/protobuf/service.h"
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/TcpConnection.h>
#include <string>
#include <functional>
#include <google/protobuf/descriptor.h>
#include <unordered_map>//框架提供的专门发布rpc服务的网络对象类
class RpcProvider
{
public://这里是框架提供给外部使用的,可以发布rpc方法的函数接口void NotifyService(google::protobuf::Service* service);//具体的服务对象类是从Service类继承而来//框架是可以接收各种RPC服务的,不能依赖具体的某一个业务。 //基类指针指向子对象 //启动rpc服务节点,开始提供rpc远程网络调用服务void Run();private://组合EventLoopmuduo::net::EventLoop m_eventLoop;//service服务类型信息struct ServiceInfo{google::protobuf::Service* m_service;//保存服务对象std::unordered_map<std::string,const google::protobuf::MethodDescriptor*> m_methodMap;//保存服务方法};//存储注册成功的服务对象和其服务方法的所有信息std::unordered_map<std::string,ServiceInfo> m_serviceMap;//新的socket连接回调void OnConnection(const muduo::net::TcpConnectionPtr&);//已建立连接用户的读写事件回调void OnMessage(const muduo::net::TcpConnectionPtr&,muduo::net::Buffer*,muduo::Timestamp);//Closure的回调操作,用于序列化rpc的响应和网络发送void SendRpcResponse(const muduo::net::TcpConnectionPtr&,google::protobuf::Message*);
};
4.完整rpcprovider.cc
#include "rpcprovider.h"
#include "mprpcapplication.h"
#include "rpcheader.pb.h"/*
service_name=> service描述(一个服务由一个服务名字对应)=》 service* 记录服务对象method_name => method方法对象
json:存储键值对,基于文本存储;数据有对应的键值
protobuf:基于二进制存储,存储效率更高;紧密存储,不携带除数据外的任何信息,整体来说protobuf存储效率更高,占用的带宽更少,同样带宽传输的数据量更大不仅可以提供类型的序列化和反序列化,还提供了service rpc方法的描述
*/
//这里是框架提供给外部使用的,可以发布rpc方法的函数接口
void RpcProvider::NotifyService(google::protobuf::Service *service)
{ServiceInfo service_info;//获取了服务对象的描述信息const google::protobuf::ServiceDescriptor* pserviceDesc=service->GetDescriptor();//获取服务的名字std::string service_name=pserviceDesc->name();//获取服务对象service的方法的数量int methodCnt=pserviceDesc->method_count();std::cout<<"service_name:"<<service_name<<std::endl;for(int i=0;i<methodCnt;++i){//获取了服务对象指定下标的服务方法的描述(抽象描述) UserService Loginconst google::protobuf::MethodDescriptor* pmethodDesc=pserviceDesc->method(i);std::string method_name=pmethodDesc->name();service_info.m_methodMap.insert({method_name,pmethodDesc});std::cout<<"method_name:"<<method_name<<std::endl;}service_info.m_service=service;m_serviceMap.insert({service_name,service_info});}// 启动rpc服务节点,开始提供rpc远程网络调用服务
void RpcProvider::Run()
{std::string ip=MprpcApplication::GetInstance().GetConfig().Load("rpcserverip");uint16_t port=atoi(MprpcApplication::GetInstance().GetConfig().Load("rpcserverport").c_str());muduo::net::InetAddress address(ip,port);//创建TcpServer对象muduo::net::TcpServer server(&m_eventLoop,address,"RpcProvider");//绑定连接回调和消息读写回调方法 ,muduo库的好处是:分离了网络代码和业务代码server.setConnectionCallback(std::bind(&RpcProvider::OnConnection, this, std::placeholders::_1));//预留1个参数std::placeholders::_1server.setMessageCallback(std::bind(&RpcProvider::OnMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));//预留3个参数std::placeholders::_1,2,3//设置muduo库的线程数量server.setThreadNum(4);std::cout<<"RpcProvider start service at ip:"<<ip<<"port:"<<port<<std::endl;//启动网络服务server.start();m_eventLoop.loop();
}//新的socket连接回调
void RpcProvider::OnConnection(const muduo::net::TcpConnectionPtr& conn)
{if(!conn->connected()){//和rpc client的连接断开了conn->shutdown();}
}
/*
在框架内部,RpcProvider和RpcConsumer协商好之间通信用的protobuf数据类型
service_name method_name args 定义proto的message类型,进行数据头的序列化和反序列化service_name method_name args_size
16UserServiceLoginzhang san123456header_size(4个字节)+header_str+args_str
10 "10"
10000 "10000"
std::string insert和copy方法
*/
// 已建立连接用户的读写事件回调 如果远程有一个rpc服务的调用请求,那么OnMessage方法就会响应
void RpcProvider::OnMessage(const muduo::net::TcpConnectionPtr& conn,muduo::net::Buffer* buffer,muduo::Timestamp)
{//网络上接收的远程rpc调用请求的字符流 Login argsstd::string recv_buf=buffer->retrieveAllAsString();//从字符流中读取前4个字节的内容uint32_t header_size = 0;recv_buf.copy((char*)&header_size,4,0);//根据header_size读取数据头的原始字符流,反序列化数据,得到rpc请求的详细消息std::string rpc_header_str=recv_buf.substr(4,header_size);mprpc::RpcHeader rpcHeader;std::string service_name;std::string method_name;uint32_t args_size;if(rpcHeader.ParseFromString(rpc_header_str)){//数据头反序列化成功service_name=rpcHeader.service_name();method_name=rpcHeader.method_name();args_size=rpcHeader.args_size();}else{//数据头反序列化失败std::cout<<"rpc_header_str:"<<rpc_header_str<<" parse error!"<<std::endl;return;}//获取rpc方法参数的字符流数据std::string args_str=recv_buf.substr(4+header_size,args_size);//打印调试信息std::cout<<"===================================================="<<std::endl;std::cout<<"header_size:"<<header_size<<std::endl;std::cout<<"rpc_header_str:"<<rpc_header_str<<std::endl;std::cout<<"service_name:"<<service_name<<std::endl;std::cout<<"method_name:"<<method_name<<std::endl;std::cout<<"args_str:"<<args_str<<std::endl;std::cout<<"===================================================="<<std::endl;//获取service对象和method对象auto it=m_serviceMap.find(service_name);if(it==m_serviceMap.end()){std::cout<<service_name<<" is not exist!"<<std::endl;return;}auto mit=it->second.m_methodMap.find(method_name);if(mit==it->second.m_methodMap.end()){std::cout<<service_name<<":"<<method_name<<"is not exist!"<<std::endl;return;}google::protobuf::Service* service=it->second.m_service;//获取service对象 new UserServiceconst google::protobuf::MethodDescriptor* method=mit->second;//获取method对象 Login//生成rpc方法调用的请求request和响应response参数google::protobuf::Message* request=service->GetRequestPrototype(method).New();if(!request->ParseFromString(args_str)){std::cout<<"request parse error,content:"<<args_str<<std::endl;return;}google::protobuf::Message* response=service->GetResponsePrototype(method).New();//给下面的method方法的调用,绑定一个Closure的回调函数google::protobuf::Closure* done=google::protobuf::NewCallback<RpcProvider,const muduo::net::TcpConnectionPtr&,google::protobuf::Message*>(this,&RpcProvider::SendRpcResponse,conn,response);//在框架上根据远端rpc请求,调用当前rpc节点上发布的方法//new UserService().Login(controller,request,response,done)service->CallMethod(method,nullptr,request,response,done);
}// Closure的回调操作,用于序列化rpc的响应和网络发送
void RpcProvider::SendRpcResponse(const muduo::net::TcpConnectionPtr &conn, google::protobuf::Message *response)
{std::string response_str;if(response->SerializeToString(&response_str))//response进行序列化{//序列化成功后,通过网络把rpc方法执行的结果发送给rpc的调用方conn->send(response_str);}else{std::cout<<"serialize response_str error!"<<std::endl;}conn->shutdown();//模拟http的短链接服务,由rpcprovider主动断开连接
}
通过onmessage,muduo库接受过来远程的字符流以后,通过参数的解析,拿到响应的service和method,然后再绑定一个回调,动态的创建这个方法对应的request和response,然后由这个框架调用这个方法,把响应的参数传到业务层去。
业务层做的事情就是从由框架进行反序列化好的请求中(request),拿数据做本地业务,填响应值再调用回调,最后done执行run,调用的是绑定的回调(SendRpcResponse)


响应对象的序列化,序列化为字符流后,再由网络发送到rpc的调用,由rpcprovider主动断开连接。
相关文章:
RpcRrovider分发rpc服务(OnMessage和Closure回调)
目录 1.完善rpcprovider.cc的OnConnection 2.完善rpcprovider.cc的OnMessage 3.完整rpcprovider.h 4.完整rpcprovider.cc 这篇文章主要完成,protobuf实现的数据序列化和反序列化。 1.完善rpcprovider.cc的OnConnection rpc的请求是短连接的,请求一次…...
分解+降维+预测!多重创新!直接写核心!EMD-KPCA-Transformer多变量时间序列光伏功率预测
分解降维预测!多重创新!直接写核心!EMD-KPCA-Transformer多变量时间序列光伏功率预测 目录 分解降维预测!多重创新!直接写核心!EMD-KPCA-Transformer多变量时间序列光伏功率预测效果一览基本介绍程序设计参…...
【Python】MacBook M系列芯片Anaconda下载Pytorch,并开发一个简单的数字识别代码(附带踩坑记录)
文章目录 配置镜像源下载Pytorch验证使用Pytorch进行数字识别 配置镜像源 Anaconda下载完毕之后,有两种方式下载pytorch,一种是用页面可视化的方式去下载,另一种方式就是直接用命令行工具去下载。 但是由于默认的Anaconda走的是外网&#x…...
自定义控件动画篇(四)ObjectAnimator的使用
ObjectAnimator 是 Android 属性动画框架中的一个重要组件,它允许你针对特定属性的值进行动画处理。与 ValueAnimator 相比,ObjectAnimator 更专注于 UI 组件,可以直接作用于视图的属性,如位置、尺寸、透明度等,而无需…...
实现List接口的ArrayList和LinkedList
package study;import java.util.*;public class day01_list {public static void main(String[] args) {// <Integer> 这个尖括号表示的是 Java 的泛型(Generics)// 泛型是 Java 5 引入的一项特性,它允许你在 类、接口和方法 中使用类…...
下拉选择输入框(基于elment-ui)
最近在需求中,需要有一个下拉选择功能,又得可以输入,在 element-ui 官网找了,发现没有适合的,然后在修炼 cv 大法的我,也在网上看了一下,但是也都感觉不合适,所以就自己写了两个&…...
CPP入门:日期类的构建
目录 1.日期类的成员 2.日期类的成员函数 2.1构造和析构函数 2.2检查日期合法 2.3日期的打印 2.4操作符重载 2.4.1小于号 2.4.2等于号 2.4.3小于等于号 2.4.4大于号 2.4.5大于等于号 2.4.6不等号 2.4.7加等的实现 2.4.8加的实现 2.4.9减去一个天数的减等实现 2.4.10…...
springboot学习,如何用redission实现分布式锁
目录 一、springboot框架介绍二、redission是什么三、什么是分布式锁四、如何用redission实现分布式锁 一、springboot框架介绍 Spring Boot是一个开源的Java框架,由Pivotal团队(现为VMware的一部分)于2013年推出。它旨在简化Spring应用程序…...
【MySQL】如果表被锁可以尝试看一下事务
今天在MySQL中删除表的时候,发现无法删除,一执行drop,navicat就卡死。 通过 SHOW PROCESSLIST显示被锁了 kill掉被锁的进程后依旧被锁 最后发现是由于存在为执行完的事务 SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX; kill掉这些事务以…...
Datawhale - 角色要素提取竞赛
文章目录 赛题要求一、赛事背景二、赛事任务三、评审规则1.平台说明2.数据说明3.评估指标4.评测及排行 四、作品提交要求五、 运行BaselineStep1:下载相关库Step2:配置导入Step3:模型测试Step4:数据读取Step5:Prompt设…...
【Sql-驯化】sql中对时间的处理方法技巧总结
【Sql-驯化】sql中对时间的处理方法技巧总结 本次修炼方法请往下查看 🌈 欢迎莅临我的个人主页 👈这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合,智慧小天地! 🎇 免费获取相关内容文档关注:微信公众…...
TFD那智机器人仿真离线程序文本转换为现场机器人程序
TFD式样那智机器人离线程序通过Process Simulation、DELMIA等仿真软件为载体给机器人出离线,下载下来的文本程序,现场机器人一般是无法导入及识别出来的。那么就需要TFD on Desk TFD控制器来进行转换,才能导入现场机器人读取程序。 导入的文…...
贪心+后缀和,CF 1903C - Theofanis‘ Nightmare
一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1903C - Theofanis Nightmare 二、解题报告 1、思路分析 我们任意一种分组其实都是若干个后缀和相加 比如我们分成了三组,第一组的数被加了一次,第二组的数被加了两次,第…...
10分钟完成微信JSAPI支付对接过程-JAVA后端接口
引入架包 <dependency><groupId>com.github.javen205</groupId><artifactId>IJPay-WxPay</artifactId><version>${ijapy.version}</version></dependency>配置类 package com.joolun.web.config;import org.springframework.b…...
如何寻找一个领域的顶级会议,并且判断这个会议的影响力?
如何寻找一个领域的顶级会议,并且判断这个会议的影响力? 会议之眼 快讯 很多同学都在问:学术会议不是期刊,即使被SCI检索,也无法查询影响因子。那么如何知道各个领域的顶级会议,并对各个会议有初步了解呢…...
真的假不了,假的真不了
大家好,我是瑶琴呀,拥有一头黑长直秀发的女程序员。 最近,17岁的中专生姜萍参加阿里巴巴 2024 年的全球数学竞赛,取得了 12 名的好成绩,一时间在网上沸腾不止。 从最开始的“数学天才”,到被质疑ÿ…...
看完这篇文章你就知道什么是未来软件开发的方向了!即生成式AI在软件开发领域的革新=CodeFlying
从最早的UGC(用户生成内容)到PGC(专业生成内容)再到AIGC(人工智能生成内容)体现了web1.0→web2.0→web3.0的发展历程。 毫无疑问UGC已经成为了当前拥有群体数量最大的内容生产方式。 同时随着人工智能技术…...
HTML5五十六个民族网站模板源码
文章目录 1.设计来源高山族1.1 登录界面演示1.2 注册界面演示1.3 首页界面演示1.4 中国民族界面演示1.5 关于高山族界面演示1.6 联系我们界面演示 2.效果和源码2.1 动态效果2.2 源代码2.3 源码目录 源码下载 作者:xcLeigh 文章地址:https://blog.csdn.ne…...
Linux_fileio实现copy文件
参考韦东山老师教程:https://www.bilibili.com/video/BV1kk4y117Tu?p12 目录 1. 通过read方式copy文件2. 通过mmap映射方式copy文件 1. 通过read方式copy文件 copy文件代码: #include <sys/types.h> #include <sys/stat.h> #include <…...
【JavaEE精炼宝库】多线程进阶(2)synchronized原理、JUC类——深度理解多线程编程
一、synchronized 原理 1.1 基本特点: 结合上面的锁策略,我们就可以总结出,synchronized 具有以下特性(只考虑 JDK 1.8): 开始时是乐观锁,如果锁冲突频繁,就转换为悲观锁。 开始是轻量级锁实现ÿ…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
使用homeassistant 插件将tasmota 接入到米家
我写一个一个 将本地tasmoat的的设备同通过ha集成到小爱同学的功能,利用了巴法接入小爱的功能,将本地mqtt转发给巴法以实现小爱控制的功能,前提条件。1需要tasmota 设备, 2.在本地搭建了mqtt服务可, 3.搭建了ha 4.在h…...

