grpc-教程(golang版)
目录
一、介绍
二、环境准备
三、Golang中使用grpc
1.编写protobuf文件
2.服务端
3.客户端
四、proto文件详解
1.proto语法
2.数据类型
基本数据类型
数组类型
map类型
嵌套类型
编写风格
3.多服务
4.多个proto文件
五、流式传输
1.普通rpc
2.服务器流式
3.客户端流式
4.双向流
六、配套代码
一、介绍
RPC
是Remote Procedure Call
的简称,中文叫远程过程调用,简单的说,就是调用远程方法和调用本地方法一样
那么grpc就是由 google
开发的一个高性能、通用的开源RPC
框架
官网地址:Introduction to gRPC | gRPC
- gRPC是一种现代开源高性能远程过程调用(RPC)框架,可在任何环境中运行。
- 它可以高效地连接数据中心内的服务,并支持负载平衡、跟踪、健康检查和身份验证等插件功能。
- 它适用于分布式计算的最后一英里,以连接设备、移动应用程序和浏览器到后端服务。
- 公司已使用gRPC连接其环境中的多个服务,从连接少数服务到跨多种语言的数据中心内数百种服务。
- gRPC最初由谷歌创建,用于连接在其数据中心内和跨越其数据中心的大量微服务。
二、环境准备
以Golang使用为例,只需要在windows上安装protoc转换工具
官网地址:Go | gRPC
# 下载网址:
https://github.com/protocolbuffers/protobuf/releases/download/v3.9.0/protoc-3.9.0-win64.zip
# go语言需要安装的依赖
go get github.com/golang/protobuf/proto
go get google.golang.org/grpc
go install github.com/golang/protobuf/protoc-gen-go
安装好之后,需要将protoc的bin目录添加到环境变量中
还需要将protoc-gen-go.exe的目录添加到环境变量中
刚刚添加之后,可能需要重启电脑或者重启goland,才能在goland的terminal中使用
三、Golang中使用grpc
整体结构如图:
1.编写protobuf文件
现在还没有学过怎么编写,不用担心,先复制粘贴就行了,主要是用于测试环境是否正常
创建文件夹 /grpc_proto 在该文件夹中创建文件 hello.proto ,编写内容如下:
syntax = "proto3"; // 指定proto版本
package hello_grpc; // 指定默认包名// 指定golang包名
option go_package = "/hello_grpc";//定义rpc服务
service HelloService {// 定义函数rpc SayHello (HelloRequest) returns (HelloResponse) {}
}// HelloRequest 请求内容
message HelloRequest {string name = 1;string message = 2;
}// HelloResponse 响应内容
message HelloResponse{string name = 1;string message = 2;
}
在文件夹 /grpc_proto 中执行命令:protoc -I . --go_out=plugins=grpc:. .\hello.proto
或者编写set.bat批处理文件,方便使用,内容如下:
protoc -I . --go_out=plugins=grpc:.\grpc_proto .\grpc_proto\hello.proto
2.服务端
package mainimport ("context""fmt""google.golang.org/grpc""google.golang.org/grpc/grpclog""net""oslee/grpc_study/1base/grpc_proto/hello_grpc"
)// HelloServer 得有一个结构体,需要实现这个服务的全部方法,叫什么名字不重要
type HelloServer struct {
}func (HelloServer) SayHello(ctx context.Context, request *hello_grpc.HelloRequest) (*hello_grpc.HelloResponse, error) {fmt.Println("入参:", request.Name, request.Message)return &hello_grpc.HelloResponse{Name: "server",Message: "hello " + request.Name,}, nil
}func main() {// 监听端口listen, err := net.Listen("tcp", ":8080")if err != nil {grpclog.Fatalf("Failed to listen: %v", err)}// 创建一个gRPC服务器实例。s := grpc.NewServer()server := HelloServer{}// 将server结构体注册为gRPC服务。hello_grpc.RegisterHelloServiceServer(s, &server)fmt.Println("grpc server running :8080")// 开始处理客户端请求。err = s.Serve(listen)
}
3.客户端
package mainimport ("context""fmt""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""log""oslee/grpc_study/1base/grpc_proto/hello_grpc"
)func main() {addr := ":8080"// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。// 此处使用不安全的证书来实现 SSL/TLS 连接conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))}defer conn.Close()// 初始化客户端client := hello_grpc.NewHelloServiceClient(conn)result, err := client.SayHello(context.Background(), &hello_grpc.HelloRequest{Name: "client",Message: "hello",})fmt.Println(result, err)
}
调用结果如下:
四、proto文件详解
1.proto语法
- service 对应的就是go里面的接口,可以作为服务端,客户端
- rpc 对应的就是结构体中的方法
- message对应的也是结构体
2.数据类型
基本数据类型
message Request {
double a1 = 1;
float a2 = 2;
int32 a3 = 3;
uint32 a4 = 4;
uint64 a5 = 5;
sint32 a6 = 6;
sint64 a7 = 7;
fixed32 a8 = 8;
fixed64 a9 = 9;
sfixed32 a10 = 10;
sfixed64 a11 = 11;
bool a12 = 12;
string a13 = 13;
bytes a14 = 14;
}
对应go类型
type Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFieldsA1 float64 `protobuf:"fixed64,1,opt,name=a1,proto3" json:"a1,omitempty"`
A2 float32 `protobuf:"fixed32,2,opt,name=a2,proto3" json:"a2,omitempty"`
A3 int32 `protobuf:"varint,3,opt,name=a3,proto3" json:"a3,omitempty"`
A4 uint32 `protobuf:"varint,4,opt,name=a4,proto3" json:"a4,omitempty"`
A5 uint64 `protobuf:"varint,5,opt,name=a5,proto3" json:"a5,omitempty"`
A6 int32 `protobuf:"zigzag32,6,opt,name=a6,proto3" json:"a6,omitempty"`
A7 int64 `protobuf:"zigzag64,7,opt,name=a7,proto3" json:"a7,omitempty"`
A8 uint32 `protobuf:"fixed32,8,opt,name=a8,proto3" json:"a8,omitempty"`
A9 uint64 `protobuf:"fixed64,9,opt,name=a9,proto3" json:"a9,omitempty"`
A10 int32 `protobuf:"fixed32,10,opt,name=a10,proto3" json:"a10,omitempty"`
A11 int64 `protobuf:"fixed64,11,opt,name=a11,proto3" json:"a11,omitempty"`
A12 bool `protobuf:"varint,12,opt,name=a12,proto3" json:"a12,omitempty"`
A13 string `protobuf:"bytes,13,opt,name=a13,proto3" json:"a13,omitempty"`
A14 []byte `protobuf:"bytes,14,opt,name=a14,proto3" json:"a14,omitempty"`
}
标量类型
.proto Type | 解释 | Go Type |
---|---|---|
double | float64 | |
float | float32 | |
int32 | 使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代 | int32 |
uint32 | 使用变长编码 | uint32 |
uint64 | 使用变长编码 | uint64 |
sint32 | 使用变长编码,这些编码在负值时比int32高效的多 | int32 |
sint64 | 使用变长编码,有符号的整型值。编码时比通常的int64高效 | int64 |
fixed32 | 总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效。 | uint32 |
fixed64 | 总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。 | uint64 |
sfixed32 | 总是4个字节 | int32 |
sfixed64 | 总是8个字节 | int64 |
bool | bool | |
string | 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本 | string |
bytes | 可能包含任意顺序的字节数据 | []byte |
标量类型如果没有被赋值,则不会被序列化,解析时,会赋予默认值
- strings:空字符串
- bytes:空序列
- bools:false
- 数值类型:0
数组类型
message ArrayRequest {
repeated int64 a1 = 1;
repeated string a2 = 2;
repeated Request request_list = 3;
}
对应go类型
type ArrayRequest struct {
A1 []int64
A2 []string
RequestList []*Request
}
map类型
键只能是基本类型
message MapRequest {
map<int64, string> m_i_s = 1;
map<string, bool> m_i_b = 2;
map<string, ArrayRequest> m_i_arr = 3;
}
对应go类型
type MapRequest struct {
MIS map[int64]string
MIB map[string]bool
MIArr map[string]*ArrayRequest
}
嵌套类型
message Q1 {
message Q2{
string name2 = 2;
}
string name1 = 1;
Q2 q2 = 2;
}
对应go类型
type Q1 struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name1 string `protobuf:"bytes,1,opt,name=name1,proto3" json:"name1,omitempty"`
Q2 *Q1_Q2 `protobuf:"bytes,2,opt,name=q2,proto3" json:"q2,omitempty"`
}
个人习惯不嵌套,分开写
编写风格
- 文件名建议下划线,例如:my_student.proto
- 包名和目录名对应
- 服务名、方法名、消息名均为大驼峰
- 字段名为下划线
3.多服务
proto文件
syntax = "proto3"; // 指定proto版本 // 指定golang包名 option go_package = "/duo_server";service VideoService {rpc Look(Request)returns(Response){} }service OrderService {rpc Buy(Request)returns(Response){} }message Request{string name = 1; } message Response{string name = 1; }
服务端
package mainimport ("context""fmt""google.golang.org/grpc""log""net""oslee/grpc_study/2duo_server/grpc_proto/duo_server"
)type VideoServer struct {
}func (VideoServer) Look(ctx context.Context, request *duo_server.Request) (res *duo_server.Response, err error) {fmt.Println("video:", request)return &duo_server.Response{Name: "server",}, nil
}type OrderServer struct {
}func (OrderServer) Buy(ctx context.Context, request *duo_server.Request) (res *duo_server.Response, err error) {fmt.Println("order:", request)return &duo_server.Response{Name: "server",}, nil
}func main() {listen, err := net.Listen("tcp", ":8080")if err != nil {log.Fatal(err)}s := grpc.NewServer()duo_server.RegisterVideoServiceServer(s, &VideoServer{})duo_server.RegisterOrderServiceServer(s, &OrderServer{})fmt.Println("grpc server程序运行在:8080")err = s.Serve(listen)
}
客户端
package mainimport ("context""fmt""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""log""oslee/grpc_study/2duo_server/grpc_proto/duo_server"
)func main() {addr := ":8080"// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。// 此处使用不安全的证书来实现 SSL/TLS 连接conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))}defer conn.Close()orderClient := duo_server.NewOrderServiceClient(conn)res, err := orderClient.Buy(context.Background(), &duo_server.Request{Name: "client",})fmt.Println(res, err)videoClient := duo_server.NewVideoServiceClient(conn)res, err = videoClient.Look(context.Background(), &duo_server.Request{Name: "client",})fmt.Println(res, err)}
4.多个proto文件
当项目大起来之后,会有很多个service,rpc,message
我们会将不同服务放在不同的proto文件中,还可以放一些公共的proto文件
本质就是生成go文件,需要在一个包内
proto文件
common.proto
syntax = "proto3"; package proto; option go_package = "/proto";message Request{string name = 1; } message Response{string name = 1; }order.proto
syntax = "proto3"; package proto; option go_package = "/proto"; import "common.proto";service OrderService {rpc Look(Request)returns(Response){} }video.proto
syntax = "proto3"; package proto; option go_package = "/proto"; import "common.proto";service VideoService {rpc Look(Request)returns(Response){} }
服务端
package mainimport ("context""fmt""google.golang.org/grpc""log""net""oslee/grpc_study/3duo_proto/grpc_proto/proto"
)type VideoServer struct {
}func (VideoServer) Look(ctx context.Context, request *proto.Request) (res *proto.Response, err error) {fmt.Println("video:", request)return &proto.Response{Name: "server",}, nil
}type OrderServer struct {
}func (OrderServer) Look(ctx context.Context, request *proto.Request) (res *proto.Response, err error) {fmt.Println("order:", request)return &proto.Response{Name: "server",}, nil
}func main() {listen, err := net.Listen("tcp", ":8080")if err != nil {log.Fatal(err)}s := grpc.NewServer()proto.RegisterVideoServiceServer(s, &VideoServer{})proto.RegisterOrderServiceServer(s, &OrderServer{})fmt.Println("grpc server程序运行在:8080")err = s.Serve(listen)
}
客户端
package mainimport ("context""fmt""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""log""oslee/grpc_study/3duo_proto/grpc_proto/proto"
)func main() {addr := ":8080"// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。// 此处使用不安全的证书来实现 SSL/TLS 连接conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))}defer conn.Close()orderClient := proto.NewOrderServiceClient(conn)res, err := orderClient.Look(context.Background(), &proto.Request{Name: "client",})fmt.Println(res, err)videoClient := proto.NewVideoServiceClient(conn)res, err = videoClient.Look(context.Background(), &proto.Request{Name: "client",})fmt.Println(res, err)
}
五、流式传输
1.普通rpc
一问一答式,文章前面已讲
2.服务器流式
建立连接后,不知道服务端什么时候发送完毕,使用场景:下载文件
proto文件
syntax = "proto3";
option go_package = "/proto";message Request {string name = 1;
}message FileResponse{string file_name = 1;bytes content = 2;
}
service ServiceStream{rpc DownLoadFile(Request)returns(stream FileResponse){}
}
服务端
package mainimport ("fmt""google.golang.org/grpc""io""log""net""os""oslee/grpc_study/4download/grpc_proto/proto"
)type ServiceStream struct{}func (ServiceStream) DownLoadFile(request *proto.Request, stream proto.ServiceStream_DownLoadFileServer) error {fmt.Println(request)file, err := os.Open("F:\\yckj\\workspace_gitee\\1own\\os_lee\\go_grpc_study\\res\\protoc-3.9.0-win64.zip")if err != nil {return err}defer file.Close()for {buf := make([]byte, 2048)_, err = file.Read(buf)if err == io.EOF {break}if err != nil {break}stream.Send(&proto.FileResponse{Content: buf,})}return nil
}func main() {listen, err := net.Listen("tcp", ":8080")if err != nil {log.Fatal(err)}server := grpc.NewServer()proto.RegisterServiceStreamServer(server, &ServiceStream{})server.Serve(listen)
}
客户端
package mainimport ("bufio""context""fmt""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""io""log""os""oslee/grpc_study/4download/grpc_proto/proto"
)func main() {addr := ":8080"// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。// 此处使用不安全的证书来实现 SSL/TLS 连接conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))}defer conn.Close()// 初始化客户端client := proto.NewServiceStreamClient(conn)stream, err := client.DownLoadFile(context.Background(), &proto.Request{Name: "张三",})file, err := os.OpenFile("F:\\yckj\\workspace_gitee\\1own\\os_lee\\go_grpc_study\\res\\protoc-3.9.0-win64_down.zip", os.O_CREATE|os.O_WRONLY, 0600)if err != nil {log.Fatalln(err)}defer file.Close()writer := bufio.NewWriter(file)var index intfor {index++response, err := stream.Recv()if err == io.EOF {break}fmt.Printf("第%d 次, 写入 %d 数据\n", index, len(response.Content))writer.Write(response.Content)}writer.Flush()
}
3.客户端流式
建立连接后,不知道客户端什么时候发送完毕,使用场景:上传文件
proto文件
syntax = "proto3";
option go_package = "/proto";
message Response {string Text = 1;
}
message FileRequest{string file_name = 1;bytes content = 2;
}
service ClientStream{rpc UploadFile(stream FileRequest)returns(Response){}
}
服务端
package mainimport ("bufio""fmt""google.golang.org/grpc""io""log""net""os""oslee/grpc_study/5upload/grpc_proto/proto"
)type ClientStream struct{}func (ClientStream) UploadFile(stream proto.ClientStream_UploadFileServer) error {file, err := os.OpenFile("F:\\yckj\\workspace_gitee\\1own\\os_lee\\go_grpc_study\\res\\protoc-3.9.0-win64_up.zip", os.O_CREATE|os.O_WRONLY, 0600)if err != nil {log.Fatalln(err)}defer file.Close()writer := bufio.NewWriter(file)var index intfor {index++response, err := stream.Recv()if err == io.EOF {break}writer.Write(response.Content)fmt.Printf("第%d次", index)}writer.Flush()stream.SendAndClose(&proto.Response{Text: "完毕了"})return nil
}func main() {listen, err := net.Listen("tcp", ":8080")if err != nil {log.Fatal(err)}server := grpc.NewServer()proto.RegisterClientStreamServer(server, &ClientStream{})server.Serve(listen)
}
客户端
package mainimport ("context""fmt""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""io""log""os""oslee/grpc_study/5upload/grpc_proto/proto"
)func main() {addr := ":8080"// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。// 此处使用不安全的证书来实现 SSL/TLS 连接conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))}defer conn.Close()// 初始化客户端client := proto.NewClientStreamClient(conn)stream, err := client.UploadFile(context.Background())file, err := os.Open("F:\\yckj\\workspace_gitee\\1own\\os_lee\\go_grpc_study\\res\\protoc-3.9.0-win64.zip")if err != nil {log.Fatalln(err)}defer file.Close()for {buf := make([]byte, 2048)_, err = file.Read(buf)if err == io.EOF {break}if err != nil {break}stream.Send(&proto.FileRequest{FileName: "x.png",Content: buf,})}response, err := stream.CloseAndRecv()fmt.Println(response, err)
}
4.双向流
使用场景:聊天室
proto文件
syntax = "proto3";
option go_package = "/proto";message Request {string name = 1;
}
message Response {string Text = 1;
}service BothStream{rpc Chat(stream Request)returns(stream Response){}
}
服务端
package mainimport ("fmt""google.golang.org/grpc""log""net""oslee/grpc_study/6chat/grpc_proto/proto"
)type BothStream struct{}func (BothStream) Chat(stream proto.BothStream_ChatServer) error {for i := 0; i < 10; i++ {request, _ := stream.Recv()fmt.Println(request)stream.Send(&proto.Response{Text: "你好",})}return nil
}func main() {listen, err := net.Listen("tcp", ":8080")if err != nil {log.Fatal(err)}server := grpc.NewServer()proto.RegisterBothStreamServer(server, &BothStream{})server.Serve(listen)
}
客户端
package mainimport ("context""fmt""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""log""oslee/grpc_study/6chat/grpc_proto/proto"
)func main() {addr := ":8080"// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。// 此处使用不安全的证书来实现 SSL/TLS 连接conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))}defer conn.Close()// 初始化客户端client := proto.NewBothStreamClient(conn)stream, err := client.Chat(context.Background())for i := 0; i < 10; i++ {stream.Send(&proto.Request{Name: fmt.Sprintf("第%d次", i),})response, err := stream.Recv()fmt.Println(response, err)}
}
六、配套代码
代码下载地址:
go_grpc_study: Golang使用grpc教程
相关文章:

grpc-教程(golang版)
目录 一、介绍 二、环境准备 三、Golang中使用grpc 1.编写protobuf文件 2.服务端 3.客户端 四、proto文件详解 1.proto语法 2.数据类型 基本数据类型 数组类型 map类型 嵌套类型 编写风格 3.多服务 4.多个proto文件 五、流式传输 1.普通rpc 2.服务器流式 …...

Spring与Spring Boot的区别:从框架设计到应用开发
这是我自己开发的一款小程序,感兴趣的可以体验一下: 进入正题: 在Java开发领域,Spring和Spring Boot都是备受推崇的框架,它们为开发人员提供了丰富的功能和便捷的开发体验。然而,许多人对它们之间的区别仍…...

React Hooks 全解: 常用 Hooks 及使用场景详解
React Hooks 是 React 16.8 版本引入的一项重要特性,它极大地简化和优化了函数组件的开发过程。 React 中常用的 10 个 Hooks,包括 useState、useEffect、useContext、useReducer、useCallback、useMemo、useRef、useLayoutEffect、useImperativeHandle 和 useDebugValue。这些…...

第十三届蓝桥杯真题:x进制减法,数组切分,gcd,青蛙过河
目录 x进制减法 数组切分 gcd 青蛙过河 x进制减法 其实就是一道观察规律的题。你发现如果a这个位置上的数x,b这个位置上的数是y,那么此位置至少是max(x,y)1进制。一定要把位置找对啊 #include <bits/stdc.h> using namespace std; typedef l…...
JavaEE初阶Day 6:多线程(4)
目录 Day 6:多线程(4)1. 线程不安全的原因2. 锁3. synchronized Day 6:多线程(4) 前序:针对Day 5结尾的count 多线程的执行,是随机调度抢占式的执行模式,某个线程执行指…...

微信小程序 django+nodejs电影院票务售票选座系统324kd
小程序Android端运行软件 微信开发者工具/hbuiderx uni-app框架:使用Vue.js开发跨平台应用的前端框架,编写一套代码,可编译到Android、小程序等平台。 前端:HTML5,CSS3 VUE 后端:java(springbootssm)/python(flaskdja…...

基于springboot实现桂林旅游景点导游平台管理系统【项目源码+论文说明】计算机毕业设计
基于springboot实现桂林旅游景点导游平台管理系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了桂林旅游景点导游平台的开发全过程。通过分析桂林旅游景点导游平台管理的不足,创建了一个计算…...

idea 开发serlvet汽车租赁管理系统idea开发sqlserver数据库web结构计算机java编程layUI框架开发
一、源码特点 idea开发 java servlet 汽车租赁管理系统是一套完善的web设计系统sqlserver数据库 系统采用serlvetdaobean mvc 模式开发,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 java se…...

Unity之PUN实现多人联机射击游戏的优化(Section 3)
目录 💣一、准备工作 💣二、生成弹头脚本的编写 💣三、实现发射和伤害同步 手雷都加了在给狗剩加个火箭筒不过分吧。效果看GIF动图,分别是单机和联机的效果。 添加火箭筒依旧是在原有的基础上更改,我查看火箭筒模型…...

PDF锐化
PDF Shaper Ultimate(pdf转图片) 编辑->添加文件->选中一个要处理的pdf 操作->转换->PDF转为图片 ComicEnhancerPro设置(把图片锐化) PDF Shaper Ultimate(图片转pdf) 编辑-添加图片->选中所有锐化处理后的图片 转换->图片转为pdf(会把所有图…...
【python和java】
如何理解java和python的不同,在java中,先有类,类生出对象,对象承载数据。而python是直接数据,没有类的概念 理解 Java 和 Python 在面向对象编程(OOP)方面的不同,关键在于理解它们各…...

C盘满了怎么办,清理工具TreeSize
TreeSize是一款强大的磁盘空间分析工具,它可以帮助用户轻松地找出电脑中占用空间最多的文件和程序,从而让用户进行针对性地删除或卸载。 占用空间很小 下载链接:https://pan.quark.cn/s/bea23ed6b1d3...

【vue】watch 侦听器
watch:可监听值的变化,旧值和新值 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><titl…...

校招生如何准备软件测试、测试开发岗位的面试?
校招生如何准备软件测试、测试开发岗位的面试? 求职建议 大家都很困惑如何学习测试?如何准备测试方面的面试? 我有朋友是做研发的,他认为测试不用准备,直接用开发的简历就行。也有人认为要学习一些测试理论…...
蓝桥杯抱佛脚篇~
文章目录 基础语法输入输出集合(set)排序 基础语法 输入输出 # 输入一个数 nint(input())# 输入两、三个数,例如:1 2 或者 1 2 3 x,y map(int,input().split())# 输入数组 # ——— 1 —— nums[int(i) for i in input().split()] print(n…...
基于springboot的大学城水电管理系统源码数据库
基于springboot的大学城水电管理系统源码数据库 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了大学城水电管理系统的开发全过程。通过分析大学城水电管理系统管理的不足,创建了一个计算机管理大学城水…...

AI大模型探索之路-应用篇2:Langchain框架ModelIO模块—数据交互的秘密武器
目录 前言 一、概述 二、Model 三、Prompt 五、Output Parsers 总结 前言 随着人工智能技术的不断进步,大模型的应用场景越来越广泛。LangChain框架作为一个创新的解决方案,专为处理大型语言模型的输入输出而设计。其中,Model IO&#…...
【SSH】群晖开启ssh访问
群晖开启ssh访问 假设 你需要设置群晖 账号 test-user 开启ssh访问 设置 你的 test-user 为管理员权限 否则你无法通过cmd 面板 连接访问 群晖你需要哪个账号 就使用哪个账号终端 cmd连接 否则需要考虑后续创建 rsa 公密钥文件的 所属权 问题账号密码连接登录终端 ssh -p 端…...

Vue 移动端(H5)项目怎么实现页面缓存(即列表页面进入详情返回后列表页面缓存且还原页面滚动条位置)keep-alive缓存及清除keep-alive缓存
一、需求 产品要求:Vue移动端项目进入列表页,列表页需要刷新,而从详情页返回列表页,列表页则需要缓存并且还原页面滚动条位置 二、实现思路 1、使用Vue中的keep-alive组件,keep-alive提供了路由缓存功能 2、因为我项…...

【MVCC】深入浅出彻底理解MVCC
MVCC概述 MVCC(Multi-Version Concurrency Control)即多版本并发控制。主要是为了提高数据库的并发性能而提供的,采用了不加锁的方式处理读-写并发冲突,确保了任何时刻的读操作都是非阻塞的。只需要很小的开销,就可以…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...