grpc补充机制

 客户端接收响应超时机制

划线处核心部分

syntax = "proto3";
 
option go_package = ".;protos";
 
message User {
    string username = 1;
    string password = 2;
}
 
message Msg {
    map<string, string> data = 1;
}
 
message UserRequest {
    Msg msg = 1;
}
 
message UserResponse {
    Msg msg = 1;
}
 
service UserService {
    rpc Regist(UserRequest) returns (UserResponse);
    rpc Login(UserRequest) returns (UserResponse);
}
package main

import (
	"context"
	"fmt"
	"mini/intercepter/protos"
	"net"
	"time"

	"google.golang.org/grpc"
)

// 介绍 gRPC 的拦截器的简单用法
 
type UserService struct {
	protos.UnimplementedUserServiceServer
}
 
func (*UserService) Regist(ctx context.Context, req *protos.UserRequest) (*protos.UserResponse, error) {
	user := protos.User{Username: req.Msg.GetData()["username"], Password:req.Msg.GetData()["password"] }
	_ ,err:= fmt.Println("regist:",user.Username,"-->",user.Password)
	if err != nil {
		return nil, err
	}
	return &protos.UserResponse{Msg: req.Msg}, nil
}
 
func (*UserService) Login(ctx context.Context, req *protos.UserRequest) (*protos.UserResponse, error) {

	//-----------------------------------------------------------------------------------------------------
	// 测试超时  : 客户端显示 :panic: rpc error: code = DeadlineExceeded desc = context deadline exceeded
	time.Sleep(time.Second * 5)
	//-----------------------------------------------------------------------------------------------------

	user := protos.User{Username: req.Msg.GetData()["username"], Password:req.Msg.GetData()["password"] }
	_ ,err:= fmt.Println("login:",user.Username,"-->",user.Password)
	if err != nil {
		return nil, err
	}
	return &protos.UserResponse{Msg: req.Msg}, nil
}
 
func main(){
	listen, err := net.Listen("tcp", "127.0.0.1:8080")
	if err != nil {
		panic(err)
	}
	g := grpc.NewServer()
	//g.RegisterService(&protos.UserService_ServiceDesc, &UserService{})
	protos.RegisterUserServiceServer(g, new(UserService))
	g.Serve(listen)
}
package main

import (
	"context"
	"mini/intercepter/protos"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)
 
func main() {
	dial, err:= grpc.Dial("127.0.0.1:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		panic(err)
	}
	client := protos.NewUserServiceClient(dial)
	data := map[string]string{
		"username" : "admin",
		"password" : "12345",
	}
	//-----------------------------------------------------------------------------------------------------
	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*3)
	defer cancel()
	resp, err := client.Login(ctx, &protos.UserRequest{Msg: &protos.Msg{Data: data}})
	//-----------------------------------------------------------------------------------------------------

	if err != nil {
		panic(err)
	}
	println(resp.Msg.Data["username"],"--->",resp.Msg.Data["password"])
}

grpc错误处理机制

syntax = "proto3";
 
option go_package = ".;protos";
 
message User {
    string username = 1;
    string password = 2;
}
 
message Msg {
    map<string, string> data = 1;
}
 
message UserRequest {
    Msg msg = 1;
}
 
message UserResponse {
    Msg msg = 1;
}
 
service UserService {
    rpc Regist(UserRequest) returns (UserResponse);
    rpc Login(UserRequest) returns (UserResponse);
}
package main

import (
	"context"
	"fmt"
	"mini/intercepter/protos"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)
 
 
type UserService struct {
	protos.UnimplementedUserServiceServer
}
 
func (*UserService) Regist(ctx context.Context, req *protos.UserRequest) (*protos.UserResponse, error) {
	user := protos.User{Username: req.Msg.GetData()["username"], Password:req.Msg.GetData()["password"] }
	_ ,err:= fmt.Println("regist:",user.Username,"-->",user.Password)
	if err != nil {
		return nil, err
	}
	return &protos.UserResponse{Msg: req.Msg}, nil
}
 
func (*UserService) Login(ctx context.Context, req *protos.UserRequest) (*protos.UserResponse, error) {
	user := protos.User{Username: req.Msg.GetData()["username"], Password:req.Msg.GetData()["password"] }
	_ ,err:= fmt.Println("login:",user.Username,"-->",user.Password)
	if err != nil {
		return nil, err
	}
	return &protos.UserResponse{Msg: req.Msg}, nil
}

// 服务端的拦截器:
/*
参数:之前的上下文、请求、元数据、处理函数
返回值:响应(元数据)、错误
*/
func Login_Intercepter(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error){
	// 其他要求:1. 认证 2. 日志 3. 限流 4. 监控 。。。
	fmt.Println("服务端登录拦截器来了~~~")
	// 拦截器处理
	data, err := Login_Intercepter_Handler(ctx, req)
	if err != nil {
		return nil, err
	}
	fmt.Println(data)
	// 继续处理请求
	resp, err = handler(ctx, req)
	// ... 其他处理
	return resp, err
}


func Login_Intercepter_Handler(ctx context.Context, req any) (any, error){
	data := req.(*protos.UserRequest).Msg.Data
	if data["username"] == "admin" && data["password"] == "123456" {
		return "通过拦截器", nil
	}
	// 返回错误, 需要导入两个包
	st := status.New(codes.InvalidArgument, "无效的用户名或者密码")
	return nil, status.Error(st.Code(), st.Message())
}
 
func main(){
	listen, err := net.Listen("tcp", "127.0.0.1:8080")
	if err != nil {
		panic(err)
	}
	opt := grpc.UnaryInterceptor(Login_Intercepter)
	g := grpc.NewServer(opt)
	//g.RegisterService(&protos.UserService_ServiceDesc, &UserService{})
	protos.RegisterUserServiceServer(g, new(UserService))
	g.Serve(listen)
}

还是注意看拦截器部分

package main

import (
	"context"
	"mini/intercepter/protos"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/status"
)
 
func main() {
	dial, err:= grpc.Dial("127.0.0.1:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		panic(err)
	}
	client := protos.NewUserServiceClient(dial)
	data := map[string]string{
		"username" : "admin",
		"password" : "12345",
	}
	resp, err := client.Login(context.Background(), &protos.UserRequest{Msg: &protos.Msg{Data: data}})
	if err != nil {
		st, ok := status.FromError(err)
		if !ok {
			// 非状态码指定的错误
			panic(err)
		}
		// 状态码指定的错误
		println(st.Code(), st.Message())
		return
	}
	println(resp.Msg.Data["username"],"--->",resp.Msg.Data["password"])
}

grpc的验证器机制

gRPC 进阶——Validator 验证器_protoc-gen-validate-优快云博客icon-default.png?t=O83Ahttps://blog.youkuaiyun.com/MPY_3/article/details/140420543?ops_request_misc=&request_id=&biz_id=102&utm_term=go%E7%9A%84grpc%E7%9A%84%E9%AA%8C%E8%AF%81%E5%99%A8%E6%9C%BA%E5%88%B6&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-140420543.142^v100^pc_search_result_base8&spm=1018.2226.3001.4187

<think>嗯,用户想了解gRPC协议的相关信息,包括介绍、原理和使用。首先,我需要回顾一下已有的知识,并结合用户提供的引用内容来组织回答。根据系统指令,要使用中文,并且正确应用LaTeX格式,同时生成相关问题。 首先,gRPC的介绍部分应该包括它的基本概念和核心特点。根据引用[1],gRPC使用了Protobuf作为接口定义语言和数据序列化工具,支持多种编程语言,并且基于HTTP/2协议。这些都是关键点,需要详细说明。 接下来是原理部分,需要分解gRPC的工作流程。Protobuf的作用是定义服务和消息结构,然后通过编译器生成代码。客户端和服务端通过Stub进行通信,传输层使用HTTP/2,这样可以利用多路复用和流控制等特性。这里可能需要解释HTTP/2的优势,比如二进制传输、头部压缩等,但引用中没有提到,所以可能需要依靠已有知识补充,但要确保正确性。 使用部分需要给出一个简单的例子,比如定义一个Protobuf文件,生成代码,然后编写服务端和客户端的代码示例。Python的例子比较易懂,但用户提供的引用中有Python的快速排序代码示例,可能用户对Python比较熟悉,所以选择Python作为示例语言更合适。 然后要确保回答结构清晰,分点说明,每个部分有明确的标题。同时,检查是否需要添加引用标识。引用[1]和[2]都提到了Protobuf和序列化的优势,比如客户端和服务端不需要处理JSON解析,直接使用对象,这点在原理或优势部分需要强调。 生成的相关问题需要围绕gRPC的进一步细节,比如与REST对比、性能优化、负载均衡机制、错误处理等。这些问题应该能帮助用户深入理解gRPC的不同方面。 需要注意系统级指令中的LaTeX格式,比如行内数学表达式要用$...$,但可能在gRPC的介绍中用到的技术术语不需要数学表达式,但如果有涉及性能指标或公式,需要正确应用。不过当前内容可能较少涉及数学,所以重点放在代码块和结构上。 最后,确保回答真实可靠,引用正确。用户提供的引用中,引用[1]和[2]都提到了Protobuf和序列化,以及HTTP/2的使用,这些都需要在回答中体现,并正确标注引用标识。例如,在提到Protobuf定义数据结构和生成代码时,引用[^1],在提到二进制传输和反序列化时,引用[^2]。 总结回答结构: 1. 概述:定义、核心特点 2. 核心原理:Protobuf、HTTP/2、Stub和通信流程 3. 核心优势:跨语言、高效、流式通信 4. 使用步骤:定义proto文件、生成代码、实现服务端和客户端 5. 代码示例:Python的简单例子 6. 相关问题:围绕对比、优化、机制等生成问题 需要检查是否有遗漏的重要点,比如gRPC的四种通信模式(单一请求、流请求等),但用户的问题中没有明确提到,可能在原理或优势部分简要提及。同时,确保回答中的技术术语准确,比如Stub、多路复用等。 现在开始组织语言,确保每个部分简洁明了,符合用户的要求。可能还需要注意用户之前的提问历史,但根据当前信息,只能基于现有的引用和通用知识来回答。</think>### gRPC协议详解 #### 一、协议概述 gRPC是谷歌开源的**高性能RPC框架**,核心特性包括: - 使用$Protocol\ Buffers$(Protobuf)定义接口和数据结构[^1] - 基于HTTP/2协议实现通信 - 支持跨语言开发(Python/Java/Go等) - 提供四种通信模式:单一请求、服务端流、客户端流、双向流 #### 二、核心原理 1. **接口定义** 通过.proto文件定义服务方法(Service)和消息结构(Message): ```protobuf syntax = "proto3"; service Greeter { rpc SayHello (HelloRequest) returns (HelloResponse) {} } message HelloRequest { string name = 1; } message HelloResponse { string message = 2; } ``` 2. **代码生成** Protobuf编译器生成对应语言的桩代码(Stub),包含: - 客户端:`GreeterStub` - 服务端:`GreeterServicer` [^1] 3. **通信流程** ```mermaid sequenceDiagram 客户端->>Stub: 方法调用 Stub->>HTTP/2: 序列化请求 HTTP/2-->>服务端: 二进制传输 服务端->>Servicer: 反序列化请求 Servicer-->>客户端: 序列化响应 ``` *注:二进制传输相比JSON减少30%-50%数据量[^2]* #### 三、核心优势 | 特性 | 说明 | |-----------|------------------------| | 强类型接口 | 编译时检查接口正确性 | | 多路复用 | 单连接并行处理多个请求(HTTP/2特性) | | 流式传输 | 支持持续数据流传输 | | 超时控制 | 客户端可设置精确超时时间 | #### 四、实践步骤(Python示例) 1. 安装依赖: ```bash pip install grpcio grpcio-tools ``` 2. 生成桩代码: ```bash python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. greeter.proto ``` 3. 服务端实现: ```python class Greeter(grpc.Servicer): def SayHello(self, request, context): return HelloResponse(message=f'Hello {request.name}!') server = grpc.server(futures.ThreadPoolExecutor()) greeter_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) server.add_insecure_port('[::]:50051') server.start() ``` 4. 客户端调用: ```python channel = grpc.insecure_channel('localhost:50051') stub = greeter_pb2_grpc.GreeterStub(channel) response = stub.SayHello(HelloRequest(name='World')) print(response.message) # 输出:Hello World! ``` #### 五、性能优化建议 1. 使用`grpc.Channel`连接池复用连接 2. 开启HTTP/2头部压缩 3. 合理设置最大消息长度(`grpc.max_send_message_length`) 4. 对频繁调用的方法启用缓存
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值