Golang-gRPC学习笔记,streamRPC,reflection,认证,拦截器

这篇博客介绍了Golang环境下gRPC的基本概念和使用,包括RPC服务方法(一元、服务端流、客户端流、双向流RPC),protobuf的使用,gRPC的安装和实战一元RPC的例子。还深入讨论了设置超时、启用反射服务、TLS认证以及自定义认证(token)的方法,并展示了如何实现客户端和服务端拦截器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

入门

RPC简介

RPC(Remote Procedure Call Protocol),远程调用协议。调用远程的函数实现功能。
广泛应用于分布式,微服务,解耦,跨语言通信等。RPC的目标就是把远程调用的过程透明化。
RPC把函数调用参数和返回值进行序列化,然后通过网络服务发送和接收。
在这里插入图片描述

gRPC简介

gRPC是google的开源的高可用的通用的RPC框架
gRPC使用protobuf作为接口定义语言和基础消息交换格式
在这里插入图片描述

gRPC服务方法

1.一元RPC(简单RPC)

客户端发送一个单独的请求,并且接收服务端对这个请求的单独回复,类似普通的函数调用
rpc SayHello(HelloRequest) returns (HelloResponse);

2.服务端流RPC

客户端发送一个单独的请求,服务端返回流式数据,客户端读取流式数据直到EOF,gRPC保证每个调用中的信息排序
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);

3.客户端流RPC

客户端写入流式数据,写入完成后等待服务端读取并返回单独的结果,gRPC保证每个调用中的信息排序
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);

4.双向流RPC

双方都使用读写流发送一系列消息。 这两个流是独立运行的,因此客户端和服务器可以按照自己需要的顺序进行读写,例如,服务器可以在写响应之前等待接收所有客户端消息,或者可以先读取一条消息再写入一条消息,或其他一些读写组合。 gRPC保证每个调用中的信息排序
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);

protobuf简介

google开源的成熟的语言无关,平台无关的可扩展的结构化数据序列化机制,类似xml,但是更小更快更简单。
可以通过一次定义数据结构,通过生成的源代码轻松编写和读取各种数据流以及使用多种语言的结构化数据。
protobuf需要在原型文件定义数据结构,其原型文件的扩展名是.proto

安装

protobuf

MacOS

brew的安装参考:https://brew.sh/
brew的安装命令:/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
使用brew安装protobuf:brew install protobuf
验证安装:

$ protoc --version
libprotoc 3.14.0

grpc-go

这里的话,先建立一个go mod项目,在项目下进行操作,项目名myproto:
在这里插入图片描述
然后在项目目录里运行go get -u google.golang.org/grpc来安装grpc-go
这一步是在go安装grpc库,也就是让go支持grpc

$ go get -u google.golang.org/grpc
go: google.golang.org/grpc upgrade => v1.35.0
go: google.golang.org/protobuf upgrade => v1.25.0
go: github.com/golang/protobuf upgrade => v1.4.3
go: golang.org/x/text upgrade => v0.3.5
go: golang.org/x/sys upgrade => v0.0.0-20210124154548-22da62e12c0c
go: golang.org/x/net upgrade => v0.0.0-20210119194325-5f4716e94777
go: google.golang.org/genproto upgrade => v0.0.0-20210203152818-3206188e46ba
go: downloading golang.org/x/net v0.0.0-20210119194325-5f4716e94777
go: downloading google.golang.org/genproto v0.0.0-20210203152818-3206188e46ba
go: downloading golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
go: downloading golang.org/x/text v0.3.5

golang protobuf

这一步是安装protoc-gen-go,来让protoc支持生成go代码
在项目目录下运行go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

$ go get -u github.com/golang/protobuf/{
   
   proto,protoc-gen-go} 
go: found github.com/golang/protobuf/protoc-gen-go in github.com/golang/protobuf v1.4.3
go: found github.com/golang/protobuf/proto in github.com/golang/protobuf v1.4.3
go: google.golang.org/protobuf upgrade => v1.25.0

这个时候检查一下项目的go.mod文件,应该是这样的:
在这里插入图片描述
至此环境配置完成。

实战

一元RPC

这里我们用两个数加和函数功能做例子。

编写proto文件,定义接口

在项目根目录新建目录及文件UnaryRPC/proto/unary.proto
文件内容:

//指定使用proto3(proto2,3有很多不同,不可混写)
syntax = "proto3";
//指定生成的go_package,简单来说就是生成的go代码使用什么包,因为我们想用proto这个文件夹来装这个代码,所以package proto
option go_package = ".;proto";

//定义rpc服务
//此处rpc服务的定义,一定要从服务端的角度考虑,即接受请求,处理请求并返回响应的一端
//请求接受一个SumReq(num1, num2)
//响应回发一条sum = num1 + num2
service Sum{
  rpc Sum(SumReq)returns(SumRes){}
}

message SumReq {
  int32 num1 = 1;
  int32 num2 = 2;
}

message SumRes {
  int32 sum = 1;
}

生成go rpc代码

进入命令行,切到unary.proto文件所在的目录,执行:protoc --go_out=plugins=grpc:. unary.proto
这条命令含义是在当前目录编译unary.proto,插件使用grpc
执行完毕可以在同目录看到一个unary.pb.go
来看一下生成文件的内容,重点关注:
在这里插入图片描述
我们在应用这个proto的时候:

  • 客户端调用SumClient接口的Sum方法,传入SumReq,接收SumRes
  • 服务端实现SumServer接口的Sum方法,接收SumReq,返回SumRes

编写服务端

文件:UnaryRPC/server/server.go
内容,有疑问看注释,再有疑问留评论:

package main

import (
	"context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
	"log"
	"net"

	// import UnaryRPC 生成的proto
	"myproto/UnaryRPC/proto"
)

// 实现SumServer接口
type SumServer struct{
   
   }

func (*SumServer) Sum(ctx context.Context, req *proto.SumReq) (*proto.SumRes, error) {
   
   
	// 暂时不对ctx进行处理
	return &proto.SumRes{
   
   Sum: req.Num1 + req.Num2}, nil
}

func main() {
   
   
	// 定义rpc server监听的端口
	lis, err := net.Listen("tcp", ":6012")
	if err != nil {
   
   
		log.Fatalf("failed to listen: %v", err)
	}

	// 实例化一个新的服务端对象
	s := grpc.NewServer()
	// 向服务端对象注册SumServer服务
	proto.RegisterSumServer(s, &SumServer{
   
   })
	// 注册服务端反射服务
	reflection.Register(s)

	// 启动服务
	s.Serve(lis)

	// 可配合ctx实现服务端的动态终止
	//s.Stop()
}

编写客户端

文件:UnaryRPC/client/client.go
内容,依旧是看注释:

package main

import (
	"context"
	"google.golang.org/grpc"
	"log"
	"myproto/UnaryRPC/proto"
	"time"
)

func main() {
   
   
	// 向服务端建立连接
	grpcConn, err := grpc.Dial("127.0.0.1"+":6012", grpc.WithInsecure())
	if err != nil {
   
   
		log.Fatalln(err)
	}

	// 实例化一个SumClient对象
	client := proto.NewSumClient(grpcConn)

	// 设置超时
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// 调用Sum函数
	res, err := client.Sum(ctx, &proto.SumReq{
   
   
		Num1: 54,
		Num2: 35,
	})
	if err != nil {
   
   
		log.Fatalln(err)
	}

	// 输出结果
	log.Println("the sum is", res.Sum)
}

运行展示

目前的目录结构
在这里插入图片描述

  • 服务端
    在这里插入图片描述
  • 客户端
    在这里插入图片描述

流式RPC

接口定义

文件:StreamingRPC/proto/stream.proto
内容:

syntax = "proto3";
option go_package = ".;proto";

//三个流式rpc
//GetStream服务器返回流
//PutStream客户端上传流
//DiStream双向流
service Stream{
  rpc GetStream(StreamReq)returns(stream StreamRes){}
  rpc PutStream(stream StreamReq)returns(StreamRes){}
  rpc BiStream(stream StreamReq)returns(stream StreamRes){}
}

message StreamReq {
  string data = 1;
}

message StreamRes {
  string data = 1;
}

服务端

文件:StreamingRPC/server/server.go

package main

import (
	"fmt"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苏打呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值