go grpc回顾:1、简单的grpc示例

151 阅读2分钟

本人旨在先跑代码,回头再看理论,所有文章代码根据步骤即可运行,前提是环境无误

grpc相关的环境需要自行搭建,示例有简单的 proto消息内嵌示例,grpc传值,服务端及客户端请求拦截等功能


### 一 新建一个pb目录

step1: cd pb step2: touch user.proto

user.proto内容如下

syntax = "proto3";

package pb;

option go_package="./pb";

enum Gender { Male = 0; Female=1;

} message Res{ string url=1; string title=2; }

message UserInfoReq{ string name=1; int64 age =2; Gender gender=3; repeated string Class_study =4; Res res = 5; }

message UserInfoResp{ string name=1; int64 age=2; Gender gender=3; Res res= 4; repeated string study=5; }

service UserService{ rpc Register(UserInfoReq)returns(UserInfoResp); }

运行命令如下

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

参数说明:

--go_out 生成go的pb文件路径 # 其他语言就是 ex:java_out....   
--go-grpc_out 生成go的grpc.pb.go文件的路径

--go_opt=paths=source_relative  # 默认是import 
--go-grpc_opt=paths=source_relative # 默认是import  

默认的imort 路径 就是指option go_package='/pb'路径 
imort模式完整的目录关系如下:
go_out/$go_package/pb_filename.pb.go
source_relative模式完整的目录关系如下:
go_out/$pb_filedir/$pb_filename.pb.go

二 grpc server

在pb同级目录新建server文件夹

setp1 cd server
step2 touch server.go

server.go

package main

import ( "context" "errors" "fmt" "grpc_pkg/simple/pb" "log" "net" "time"

"google.golang.org/grpc/metadata"

"google.golang.org/grpc" "google.golang.org/grpc/reflection" )

type User struct { pb.UnimplementedUserServiceServer }

func (t *User) Register(ctx context.Context, req *pb.UserInfoReq) (*pb.UserInfoResp, error) { fmt.Println(req.Gender.String()) return &pb.UserInfoResp{ Name: req.Name, Gender: req.Gender, Res: &pb.Res{ Url: req.Res.Url, Title: req.Res.Title, }, Age: req.Age, Study: req.ClassStudy, }, nil }

//2023/04/27 11:03:46 calling "/pb.UserService/Register" with request name:"HQ" age:13 res:{url:"这是url" title:"这是标题"} //Male //2023/04/27 11:03:46 finished "/pb.UserService/Register" in 9.578µs

func serverInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { log.Printf("calling %q with request %v", info.FullMethod, req.(*pb.UserInfoReq).Res) start := time.Now() resp, err = handler(ctx, req) // 获取传递的值 md, ok := metadata.FromIncomingContext(ctx) if !ok { return nil, errors.New("没有数据") } os := md.Get("client-os") fmt.Println("客户端的系统是:", os) log.Printf("finished %q in %v", info.FullMethod, time.Since(start)) // 拦截条件示例 //if os[0] == "darwin" { // return resp, errors.New("系统不对") //} return resp, err }

func main() { listen, err := net.Listen("tcp", ":8081") if err != nil { fmt.Println(err) return }

gServer := grpc.NewServer( grpc.UnaryInterceptor(serverInterceptor)) // 注册server 服务 pb.RegisterUserServiceServer(gServer, &User{})

//注册反射服务 reflection.Register(gServer)

if err := gServer.Serve(listen); err != nil { log.Fatalf("failed to serve: %v", err) } }


<font color='red'> 注意: </font>
> user结构体中内嵌了 pb.UnimplementedUserServiceServer结构体
> 原因在grpc.pb.go中有说明:
UnimplementedUserServiceServer must be embedded to have forward compatible implementations.
简单的翻译一下就是,你不内嵌,这个结构体就没办法实现对应的接口


### 三 grpc client 
在pb同级目录新建client文件夹 
> setp1 cd client  
> step2 touch client.go  

client.go

package main

import ( "context" "fmt" "grpc_pkg/simple/pb" "log" "runtime" "time"

"google.golang.org/grpc/metadata"

"google.golang.org/grpc/credentials/insecure"

"google.golang.org/grpc" )

func clientInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { log.Printf("calling %q with request %v", method, req) start := time.Now() client_t := runtime.GOOS // grpc 传值 ctx = metadata.AppendToOutgoingContext(ctx, "client-os", client_t) err := invoker(ctx, method, req, reply, cc, opts...) log.Printf("finished %q in %v", method, time.Since(start)) // 拦截条件 // if client_t !="sss"{ // return errors.new("系统有误") //} return err }

func main() { conn, err := grpc.Dial(":8081", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithUnaryInterceptor(clientInterceptor)) if err != nil { fmt.Println(err) return } defer conn.Close()

c := pb.NewUserServiceClient(conn)

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel()

res, err := c.Register(ctx, &pb.UserInfoReq{ Name: "HQ", Gender: pb.Gender_Male, Age: 13, Res: &pb.Res{ Title: "这是标题", Url: "这是url", }, })

if err != nil { fmt.Println(err) return } fmt.Println(res.Gender) fmt.Println(res.String())

}

四 调用

先启动server
在启动client

client运行结果 image.png