gRPC(狂神说)

gRPC(狂神说)

视频地址:【狂神说】gRPC最新超详细版教程通俗易懂 | Go语言全栈教程_哔哩哔哩_bilibili

1、gRPC介绍

单体架构

  • 一旦某个服务宕机,会引起整个应用不可用,隔离性差
  • 只能整体应用进行伸缩,浪费资源,可伸缩性差
  • 代码耦合在一起,可维护性差

微服务架构:

解决了单体架构的弊端,但同时引入了新的问题

  • 代码冗余
  • 服务和服务之间存在调用关系

服务拆分后,服务和服务之间发生的是进程和进程之间的调用,服务器和服务器之间的调用,那么就需要发起网络调用。

网络调用我们能立马想起的就是http,但是在微服务架构中,http虽然便捷方便,但性能较低,这时候就需要引入RPC(远程过程调用),通过自定义协议发起TCP调用,来加快传输效率。

文档:Documentation | gRPC

中文文档:gRPC 官方文档中文版_V1.0 (oschina.net)

RPC的全称是Remote Procedure Call,远程过程调用。这是一种协议,是用来屏蔽分布式计算中的各种调用细节,使得你可以像是本地调用一样直接调用一个远程的函数。

客户端服务端 沟通的过程

  1. 客户端 发送数据(以字节流的方式)
  2. 服务端 接受并解析。 根据约定知道要执行什么。然后把结果返回给客户

RPC:

  • RPC就是将上述过程封装,使其操作更加优化
  • 使用一些大家都认可的协议 使其规范化
  • 做成一些框架。直接或间接产生利益

而gRPC又是什么呢?用官方的话来说

A high performance, open source universal RPC framework

在gRPC中,我们称调用方为client,被调用方为server。跟其他的RPC框架一样,gRPC也是基于“服务定义“的思想。简单的来讲,就是我们通过某种方式来描述一个服务,这种描述方式是语言无关的。在这个"服务定义"的过程中,我们描述了我们提供的服务服务名是什么,有哪些方法可以被调用,这些方法有什么样的入参,有什么样的回参。

也就是说,在定义好了这些服务、这些方法之后,**gRPC会屏蔽底层的细节,client只需要直接调用定义好的方法,就能拿到预期的返回结果。对于server端来说,还需要实现我们定义的方法。**同样的,gRPC也会帮我们屏蔽底层的细节,我们只需要实现所定义的方法的具体逻辑即可。

你可以发现,在上面的描述过程中,所谓的”“服务定义",就跟定义接口的语义是很接近的。我更愿意理解为这是一种"约定”,双方约定好接口,然后server实现这个接口,client调用这个接口的代理对象。至于其他的细节,交给gRPC。

此外,gRPC还是语言无关的。你可以用C++作为服务端,使用Golang、java等作为客户端。为了实现这一点,我们在"定义服务“和在编码和解码的过程中,应该是做到语言无关的。

image-20240608162027789

因此,gRPC使用了Protocol Buffss。这是谷歌开源的一套成熟的数据结构序列化机制。

你可以把他当成一个代码生成工具以及序列化工具。这个工具可以把我们定义的方法,转换成特定语言的代码。比如你定义了一种类型的参数。他会帮你转换成Golang中的struct 结构体,你定义的方法,他会帮你转换成func 图数。此外,在发送请求和接受响应的时候,这个工具还会完成对应的编码和解码工作,将你即将发送的数据编码成gRPC能够传输的形式,又或者将即将接收到的数据解码为编程语言能够理解的数据格式。

**序列化:**将数据结构或对象转换成二进制串的过程
**反序列化:**将在序列化过程中所产生的二进制串转换成数据结构或者对象的过程

protobuf是谷歌开源的一种数据格式,适合高性能,对响应速度有要求的数据传输场累。因为protobuf是二进制数据格式,需要编码和解码。数据本身不具有可读性。因此只能反序列化之后得到真正可读的数据。

优势

  • 序列化后体积相比Json和XML很小,适合网络传输
  • 支持跨平台多语言
  • 消息格式升级和兼容性还不错
  • 序列化反序列化速度很快

2、安装Protobuf

安装地址:Releases · protocolbuffers/protobuf (github.com)

解压、为bin目录配置环境变量

image-20240608162808975

验证:

cmd 输入:protoc

C:\Users\27184>protoc
Usage: protoc [OPTION] PROTO_FILES
Parse PROTO_FILES and generate output based on the options given:-IPATH, --proto_path=PATH   Specify the directory in which to search forimports.  May be specified multiple times;directories will be searched in order.  If notgiven, the current working directory is used.If not found in any of the these directories,the --descriptor_set_in descriptors will bechecked for required proto file.--version                   Show version info and exit.-h, --help                  Show this text and exit.
----------------------------------------------------------------------  

安装gRPC核心库

go get google.golang.org/grpc

如果下载不下来,可能是没配置代理:

go env -w GOPROXY="https://goproxy.cn,direct"

image-20240608163206201

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

3、Proto文件编写

//这是在说明我们使用的是proto3语法。
syntax ="proto3";//这部分的内容是关于最后生成的go文件是处在哪个目录哪个包中,.代表在当前目录生成,service代表了生成的go文件的包名是service。
option go_package =".;service";//然后我们需要定义一个服务,在这个服务中需要有一个方法,这个方法可以接受客户端的参数,再返回服务端的响应。
//其实很容易可以看出,我仰定义了一个service,称为SayHe11o,这个服务中有一个rpc方法,名为SayHe1lo。
//这个方法会发送-个HelloRequest,然后返回一个HelloResponse。
service SayHello{rpc SayHello(HelloRequest)returns (HelloResponse){}
}
//message关键字,其实你可以理解为Go1ang中的结构体。
//这里比较特别的是变量后面的“赋值”。注意,这里并不是赋值,而是在定义这个变量在这个message中的位置。
message HelloRequest{string requestName = 1;// int64 age = 2;
}
message HelloResponse{string responseMsg = 1;
}

在编写完上面的内容后,在hello-server/proto目录下执行如下命令:

protoc --go_out=. hello.proto
protoc --go-grpc_out=. hello.proto

(如果出现了 --go_out: hello.pb.go: unparsable Go source: 1:3: illegal UTF-8 encoding (and 18 more errors) 的错误,请删除上述文件中的中文!!)

4、Proto文件介绍

message

message: protobuf中定义一个消息类型是通过关键字message字段指定的。消息就是需要传输的数据格式的定义

message 关键字类似于C++中的class,JAVA中的class,go中的struct

在消息中承载的数据分别对应于每一个字段,其中每个字段都有一个名字和一种类型

一个proto文件中可以定义多个消息类型

字段规则

required: 消息体中必填字段,不设置会导致编码异常。在protobuf2中使用,在protobuf3中被删去

optional: 消息体中可选字段。protobuf3没有了required,optional等说明关键字,都默认为optional

repeated: 消息体中可重复字段,重复的值的顺序会被保留在go中重复的会被定义为切片。

message HelloRequest{string requestName = 1;int64 age = 2;repeated string name = 3;
}

image-20240608181450016

消息号

在消息体的定义中,每个字段都必须要有一个唯一的标识号,标识号是[1,2^29-1]范围内的一个整数

嵌套消息

可以在其他消息类型中定义、使用消息类型,在下面的例子中,person消息就定义在Personlnfo消息内如

message PersonInfo{message Person{string name = 1;int32 height = 2;}repeated Person info = 1;
}

image-20240608181810694

服务定义

如果想要将消息类型用在RPC系统中,可以在.proto文件中定义一个RPC服务接口,protocol buffer编译器将会根据所选择的不同语言生成服务接口代码及存根。

service searchService{rpc Search(searchRequest)returns (searchResponse){}
}

上述代表表示,定义了一个RPC服务,该方法接收 searchRequest 返回 searchResponse

5、服务端代码编写

package mainimport ("context""fmt"pb "gRPC/hello-server/proto""google.golang.org/grpc""net"
)type server struct {pb.UnimplementedSayHelloServer
}func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {return &pb.HelloResponse{ResponseMsg: "hello" + " " + req.RequestName}, nil
}func main() {// 1. 开启端口listen, err := net.Listen("tcp", ":9090")if err != nil {fmt.Printf("listen error: %v", err)fmt.Println()}// 2. 创建grpc服务,在grpc服务端中注册grpcServer := grpc.NewServer()pb.RegisterSayHelloServer(grpcServer, &server{})// 3.启动服务err = grpcServer.Serve(listen)if err != nil {fmt.Printf("failed to serve: %v", err)return}}

6、客户端代码编写

package mainimport ("context""fmt"pb "gRPC/hello-server/proto""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""log"
)func main() {// 1. 连接到server端,此处禁用安全传输,没有加密和验证conn, err := grpc.Dial("127.0.0.1:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatalf("did not connect: %v", err)}defer conn.Close()// 2. 建立连接client := pb.NewSayHelloClient(conn)// 3. 执行rpc调用resp, _ := client.SayHello(context.Background(), &pb.HelloRequest{RequestName: "zwj"})fmt.Printf(resp.ResponseMsg)
}

依次启动服务端、客户端即可。

7、认证及安全传输

gRPC 是一个典型的C/S模型,需要开发客户端和服务端,客户端与服务端需要达成协议,使用某一个确认的传输协议来传输数据,
gRPC默认是使用protobuf来作为传输协议,当然也是可以使用其他自定义的协议。

image-20240608184326020

那么,客户端与服务端要通信之前,客户端如何知道自己的数据是发给哪一个明确的服务端呢?反过来,服务端是不是也需要有一种方式来弄清楚自己的数据要返回给谁呢?

那么就不得不提gRPC的认证,此处说到的认证,不是用户的身份认证,而是指多个server 和多个client之间,如何识别对方是谁,并且可以安全的进行数据传输

  • SSL/TLS认证方式(采用http2协议)
  • 基于Token的认证方式(基于安全连接)
  • 不采用任何措施的连接,这是不安全的连接(默认采用http1)
  • 自定义的身份认证

客户端和服务端之间调用,我们可以通过加入证书的方式,实现调用的安全性

TLS (Transport Laver Security,安全传输层),TLS是建立在传输层TCP协议之上的协议,服务于应用层,它的前身是SSL(Secure SocketLaver 安全套接字层),它实现了将应用层的报文进行加密后再交由TCP进行传输的功能。

TLS协议主要解决如下三个网络安全问题:

  1. 保密(message privacy),保密通过加密encryption实现,所有信息都加密传输,第三方无法嗅探
  2. 完整性(message integrity),通过MAC校验机制,一旦被篡改,通信双方会立刻发现;
  3. 认证(mutual authentication),双方认证,双方都可以配备证书,防止身份被冒充:

生产环境可以购买证书或者使用一些平台发放的免费证书

key:服务器上的私钥文件,用于对发送给客户端数据的加密,以及对从客户端接收到数据的解密。

csr:证书签名请求文件,用于提交给证书颁发机构(CA)对证书签名

crt:由证书颁发机构(CA)签名后的证书,或者是开发者自签名的证书,包含证书持有人的信息,持有人的公钥,以及签署者的签名等信息。

pem:是基于Base64编码的证书格式,扩展名包括PEM、CRT和CER。

一些名词解释:一次把http、https、tcp、udp、tls、ssl聊明白 - 二柒的博客 - 博客园 (cnblogs.com)

8、TLS认证实现

首先通过openssl生成证书和私钥

  1. 官网下载:https://www.openssl.org/source/
    • 其他人做的便捷版安装包 Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions (slproweb.com)
  2. 我们使用 便捷版安装包,一直下一步即可
  3. 配置环境变量 D:\Environment\OpenSSL-Win64\bin
  4. 命令行测试 openssl

生成证书

#1、生成私钥
openssl genrsa -out server.key 2048
#2、生成证书全部回车即可,可以不填
openssl req -new -x509 -key server.key -out server.crt -days 36500#国家名称
Country Name (2 letter code)[AU]:CN#省名称
State or Province Name (full name)[Some-State]:GuangDong#城市名称
Locality Name
(eg,city)[]Meizhou#公司组织名称
organization Name (eg,company)[Internet widgits Pty Ltd]:Xuexiangban#部门名称
organizational Unit Name (eg,section)[]go#服务器or网站名称
Common Name (e.g.server FQDN or YOUR name)[]kuangstudy#邮件
Email Address []:24736743@qq.com
#3、生成csr
openssl req -new -key server.key -out server.csr

更改openssl文件

#1)复制一份你安装的openss1的bin目录里面的openss1.cnf 文件到你项目所在的目录
#2)找到[ CA_default],打开 copy_extensions = copy (就是把前面的#去掉)
#3)找到[ req ],打开 req_extensions = v3_reg # The extensions to add to a certificate request
#4)找到[v3_req],添加 subjectAltName = @alt_names
#5)添加新的标签[ alt_names ],和标签字段
DNS.1 =*.kuangstudy.com

生成私钥信息

#生成证书私钥test.key
openssl genpkey -algorithm RSA -out test.key
#通过私钥test.key生成证书请求文件test.csr(注意cfg和cnf)
openssl req -new -nodes -key test.key -out test.csr -days 3650 -subj "/C=cn/OU=myorg/O=mycomp/CN=myname" -config ./openssl.cfg -extensions v3_req
#test.csr是上面生成的证书请求文件。ca.crt/server.key是CA证书文件和key,用来对test.csr进行签名认证。这两个文件在第一部分生成。#上述一般会有警告信息:Ignoring -days without -x509; not generating a certificate,这个警告表明,在没有指定 -x509 选项的情况下,-days 选项将被忽略。-days 选项通常用于指定自签名证书(self-signed certificate)的有效期限,而不是 CSR。因此,如果你想生成一个自签名证书,你需要添加 -x509 选项,但是这样做下面的生成SAN证书会出现错误!!
openssl req -new -nodes -key test.key -out test.csr -x509 -days 3650 -subj "/C=cn/OU=myorg/O=mycomp/CN=myname" -config ./openssl.cfg -extensions v3_req
#生成SAN证书pem
openssl x509 -req -days 365 -in test.csr -out test.pem -CA server.crt -CAkey server.key -CAcreateserial -extfile ./openssl.cfg -extensions v3_req

服务端代码

package mainimport ("context""fmt"pb "gRPC/hello-server/proto""google.golang.org/grpc""google.golang.org/grpc/credentials""net""os"
)type server struct {pb.UnimplementedSayHelloServer
}func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {return &pb.HelloResponse{ResponseMsg: "hello" + " " + req.RequestName}, nil
}func main() {cwd, err := os.Getwd()if err != nil {fmt.Println("Error getting current working directory:", err)return}fmt.Println("Current working directory:", cwd)cred, err := credentials.NewServerTLSFromFile("./key/test.pem", "./key/test.key")if err != nil {fmt.Println(err)fmt.Println("NewServerTLSFromFile error")}// 1. 开启端口listen, err := net.Listen("tcp", ":9090")if err != nil {fmt.Printf("listen error: %v", err)fmt.Println()}// 2. 创建grpc服务,在grpc服务端中注册grpcServer := grpc.NewServer(grpc.Creds(cred))pb.RegisterSayHelloServer(grpcServer, &server{})// 3.启动服务err = grpcServer.Serve(listen)if err != nil {fmt.Printf("failed to serve: %v", err)return}}

客户端代码

package mainimport ("context""fmt"pb "gRPC/hello-server/proto""google.golang.org/grpc""google.golang.org/grpc/credentials""log"
)func main() {cred, err := credentials.NewClientTLSFromFile("./key/test.pem","*.kuangstudy.com")if err != nil {fmt.Println(err)fmt.Println("NewClientTLSFromFile error")}// 1. 连接到server端,此处禁用安全传输,没有加密和验证conn, err := grpc.Dial("127.0.0.1:9090", grpc.WithTransportCredentials(cred))if err != nil {log.Fatalf("did not connect: %v", err)}defer conn.Close()// 2. 建立连接client := pb.NewSayHelloClient(conn)// 3. 执行rpc调用resp, _ := client.SayHello(context.Background(), &pb.HelloRequest{RequestName: "zwj"})fmt.Printf(resp.ResponseMsg)
}

9、自定义Token

我们先看一个gRPC提供我们的一个接口,这个接口中有两个方法,接口位于credentials 包下,这个接口需要客户端来实现

// PerRPCCredentials defines the common interface for the credentials which need to
// attach security information to every RPC (e.g., oauth2).
type PerRPCCredentials interface {// GetRequestMetadata gets the current request metadata, refreshing tokens// if required. This should be called by the transport layer on each// request, and the data should be populated in headers or other// context. If a status code is returned, it will be used as the status for// the RPC (restricted to an allowable set of codes as defined by gRFC// A54). uri is the URI of the entry point for the request.  When supported// by the underlying implementation, ctx can be used for timeout and// cancellation. Additionally, RequestInfo data will be available via ctx// to this call.  TODO(zhaoq): Define the set of the qualified keys instead// of leaving it as an arbitrary string.GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)// RequireTransportSecurity indicates whether the credentials requires// transport security.RequireTransportSecurity() bool
}

第一个方法作用是获取元数据信息,也就是客户端提供的key,alue对,context用于控制超时和取消,uri是请求入口处的uri

第二个方法的作用是否需要基于 TLS 认证进行安全传输,如果返回值是true,则必须加上TLS验证,返回值是false则不用。

客户端代码

package mainimport ("context""fmt"pb "gRPC/hello-server/proto""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""log"
)type ClientTokenAuth struct {
}func (c ClientTokenAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {return map[string]string{"appId":  "kuangshen","appKey": "123123",}, nil
}func (c ClientTokenAuth) RequireTransportSecurity() bool {return false
}func main() {var dials []grpc.DialOptiondials = append(dials, grpc.WithTransportCredentials(insecure.NewCredentials()))dials = append(dials, grpc.WithPerRPCCredentials(new(ClientTokenAuth)))//cred, err := credentials.NewClientTLSFromFile("./key/test.pem",//	"*.kuangstudy.com")//if err != nil {//	fmt.Println(err)//	fmt.Println("NewClientTLSFromFile error")//}// 1. 连接到server端,此处禁用安全传输,没有加密和验证conn, err := grpc.Dial("127.0.0.1:9090", dials...)if err != nil {log.Fatalf("did not connect: %v", err)}defer conn.Close()// 2. 建立连接client := pb.NewSayHelloClient(conn)// 3. 执行rpc调用resp, _ := client.SayHello(context.Background(), &pb.HelloRequest{RequestName: "zwj"})fmt.Printf(resp.ResponseMsg)
}

服务端代码

package mainimport ("context""errors""fmt"pb "gRPC/hello-server/proto""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""google.golang.org/grpc/metadata""net"
)type server struct {pb.UnimplementedSayHelloServer
}// SayHello 业务代码
func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {md, ok := metadata.FromIncomingContext(ctx)if !ok {return nil, errors.New("not found token")}var appId stringvar appKey stringif v, ok := md["appid"]; ok {appId = v[0]}if v, ok := md["appkey"]; ok {appKey = v[0]}fmt.Printf("appId:%s,appKey:%s", appId, appKey)fmt.Println()if appId != "kuangshen" || appKey != "123123" {return nil, errors.New("token is not valid")}return &pb.HelloResponse{ResponseMsg: "hello" + " " + req.RequestName + " " + appId + " " + appKey}, nil
}func main() {//cred, err := credentials.NewServerTLSFromFile("./key/test.pem", "./key/test.key")//if err != nil {//	fmt.Println(err)//	fmt.Println("NewServerTLSFromFile error")//}// 1. 开启端口listen, err := net.Listen("tcp", ":9090")if err != nil {fmt.Printf("listen error: %v", err)fmt.Println()}// 2. 创建grpc服务,在grpc服务端中注册grpcServer := grpc.NewServer(grpc.Creds(insecure.NewCredentials()))pb.RegisterSayHelloServer(grpcServer, &server{})// 3.启动服务err = grpcServer.Serve(listen)if err != nil {fmt.Printf("failed to serve: %v", err)return}}

gRPC将各种认证方式浓缩统一到一个凭证(credentials)上,可以单独使用一种凭证,比如只使用TLS凭证或者只使用自定义凭证,也可以多种凭证组合,gRPC提供统一的API验证机制,使研发人员使用方便,这也是gRPC设计的巧妙之处。

10、小结

image-20240609110709927

期待kubernetes呜呜呜

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/24902.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++ STL】模拟实现 string

标题:【C :: STL】手撕 STL _string 水墨不写bug (图片来源于网络) C标准模板库(STL)中的string是一个可变长的字符序列,它提供了一系列操作字符串的方法和功能。 本篇文章,我们将模拟实现STL的…

ipables防火墙

一、Linux防火墙基础 Linux 的防火墙体系主要工作在网络层,针对 TCP/IP 数据包实施过滤和限制,属于典 型的包过滤防火墙(或称为网络层防火墙)。Linux 系统的防火墙体系基于内核编码实现, 具有非常稳定的性能和高效率&…

VB7/64位VB6开发工具office插件开发-twinbasic

全新的VB7,twinbasic,支持64位开发,支持EXCEL插件开发,老外连续3年闭关修练终成正果 官方最新版下载:https://github.com/twinbasic/twinbasic/releases 汉化工具用法:把工具和Lang_Tool目录复制到Twinbasi…

SAP PP学习笔记18 - MTO(Make-to-Order):按订单生产(受注生産) 的策略 20,50,74

前面几章讲了 MTS(Make-to-Stock)按库存生产的策略(10,11,30,40,70)。 SAP PP学习笔记14 - MTS(Make-to-Stock) 按库存生产(策略10),…

ChatTTS 开源文本转语音模型本地部署、API使用和搭建WebUI界面(建议收藏)

ChatTTS(Chat Text To Speech)是专为对话场景设计的文本生成语音(TTS)模型,特别适用于大型语言模型(LLM)助手的对话任务,以及诸如对话式音频和视频介绍等应用。它支持中文和英文,还可以穿插笑声、说话间的停顿、以及语…

计算机网络ppt和课后题总结(下)

常用端口总结 计算机网络中,端口是TCP/IP协议的一部分,用于标识运行在同一台计算机上的不同服务。端口号是一个16位的数字,范围从0到65535。通常,0到1023的端口被称为“熟知端口”或“系统端口”,它们被保留给一些标准…

基于百度接口的实时流式语音识别系统

目录 基于百度接口的实时流式语音识别系统 1. 简介 2. 需求分析 3. 系统架构 4. 模块设计 4.1 音频输入模块 4.2 WebSocket通信模块 4.3 音频处理模块 4.4 结果处理模块 5. 接口设计 5.1 WebSocket接口 5.2 音频输入接口 6. 流程图 程序说明文档 1. 安装依赖 2.…

RHEL8/Centos8 install for PXE

PXE介绍 PXE(Preboot Execution Environment)是预引导执行环境的缩写。它是由Intel设计的,允许客户端计算机通过网络从服务器上加载操作系统镜像。PXE通常用于大规模部署操作系统,例如在企业或学校环境中。 PXE工作流程如下&…

【复现】含能量路由器的交直流混合配电网潮流计算

目录 1 主要内容 2 理论及模型 3 程序结果 4 下载链接 1 主要内容 程序复现《含能量路由器的交直流混合配电网潮流计算》,主要是对算例4.1进行建模分析,理论和方法按照文献所述。能量路由器(ER)作为新兴的电力元器件&#xff…

Spring Boot通过自定义注解和Redis+Lua脚本实现接口限流

😄 19年之后由于某些原因断更了三年,23年重新扬帆起航,推出更多优质博文,希望大家多多支持~ 🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 🎐 个人CSND主页——Mi…

FuTalk设计周刊-Vol.040

🔥AI漫谈 热点捕手 1、零代码定制游戏NPC,百川智能发布角色大模型 百川智能此次推出了“角色创建平台搜索增强知识库”的定制化解决方案。通过这一方案,游戏厂商无需编写任何代码,只需通过简单的文字描述,便可以快速…

IT人的拖延——都是“分心”惹的祸?

典型表现 我们说到拖延的原因有很多,还有一个原因是因为“分心太多“造成的,分心太多的拖延大致上有以下表现: 无法集中注意力: 分心太多会导致我们无法集中注意力在当前的工作任务上,我们可能会经常性地走神或者在工…

Vue12-计算属性

一、姓名案例 1-1、插值语法实现 1、v-bind v-bind的问题: 所以:v-bind是单向绑定。 2、v-model 解决v-bind的问题。 3、输出全名 方式一: 方式二: 需求优化:全名中的姓氏,只取输入框中的前三位&#xf…

VSCode数据库插件

Visual Studio Code (VS Code) 是一个非常流行的源代码编辑器,它通过丰富的插件生态系统提供了大量的功能扩展。对于数据库操作,VS Code 提供了几种插件,其中“Database Client”系列插件是比较受欢迎的选择之一,它包括了对多种数…

使用C++结合OpenCV进行图像处理与分类

⭐️我叫忆_恒心,一名喜欢书写博客的在读研究生👨‍🎓。 如果觉得本文能帮到您,麻烦点个赞👍呗! 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三…

基于STC12C5A60S2系列1T 8051单片机实现串口调试助手软件与单片机相互发送数据的RS485通信功能

基于STC12C5A60S2系列1T 8051单片机实现串口调试助手软件与单片机相互发送数据的RS485通信功能 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机串口通信介绍STC12C5A60S2系列1T 8051单片机串口通信的结构基于STC12C5A60S2系列1T 8051单片机串口通信的特殊功…

力扣 74.搜索二维矩阵

题目描述: 给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则&am…

决策树Decision Tree

目录 一、介绍发展优点缺点基本原理 二、熵1、熵2、条件熵3、信息增益4、信息增益率 三、基尼系数四、ID3算法1、建树过程2、优点3、缺点 五、C4.51、二分法处理连续变量1、流程:2、示例 2、缺点 六、CART1、连续数据处理2、离散数据处理3、CART回归原理1、均方误差…

【机器学习】机器学习引领AI:重塑人类社会的新纪元

📝个人主页🌹:Eternity._ 🌹🌹期待您的关注 🌹🌹 ❀机器学习引领AI 📒1. 引言📕2. 人工智能(AI)🌈人工智能的发展🌞应用领…

每日两题6

文章目录 删除并获得点数粉刷房子 删除并获得点数 分析 class Solution { public:int deleteAndEarn(vector<int>& nums) {const int N 10001;// 预处理int arr[N] {0};for (int& e : nums)arr[e] e;// 在 arr 上进行 打家劫舍 问题vector<int> f(N),…