grpc学习

ここあ Posted on 21 days ago 82 Views


grpc安装

  • 1.1 核心依赖安装
# 1. 安装 Protobuf 核心库
go get google.golang.org/protobuf@latest

# 2. 安装 gRPC 核心库
go get google.golang.org/grpc@latest

# 3. 安装 Protobuf 代码生成插件
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
# 4. 处理 gRPC 代码生成
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
  • 1.2 编写protobuf文件
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;
}
  • 1.3 基础 Protobuf Go 代码
protoc -I . --go_out=.\grpc_proto .\grpc_proto\hello.proto
  • 1.4 gRPC 核心 Go 代码
protoc -I . --go-grpc_out=.\grpc_proto .\grpc_proto\hello.proto

生成输出

  • 服务端, 定义一个的结构体,使其实现 Protobuf 生成的服务接口的所有方法,随后将该结构体实例注册为 gRPC 服务并启动端口监听,以接收客户端请求。
package main

import (
	"fmt"
	"grpc-study/grpc_proto/hello_grpc"
	"net"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
)

type HelloServer struct {
	hello_grpc.UnimplementedHelloServiceServer
}

func (HelloServer) SayHello(ctx context.Context, request *hello_grpc.HelloRequest) (pd *hello_grpc.HelloResponse, err error) {
	fmt.Println("入参:", request.Name, request.Message) // 打印客户端传入的参数
	pd = new(hello_grpc.HelloResponse)                  // 创建响应对象(初始化指针)
	pd.Name = "Server"                                  // 设置响应中的 Name 字段
	pd.Message = "OK"                                   // 设置响应中的 Message 字段
	return                                              // 返回响应对象和 nil 错误(表示成功)
}

func main() {
	// 监听端口:创建 TCP 监听,绑定到 8080 端口
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		grpclog.Fatalf("Failed to listen: %v", err) // 监听失败则打印日志并退出
	}

	// 创建一个 gRPC 服务器实例(可配置拦截器、tls 等,这里用默认配置)
	s := grpc.NewServer()

	// 实例化自定义的服务端结构体
	server := &HelloServer{}

	// 将服务端结构体注册到 gRPC 服务器:告诉 gRPC 框架,这个服务器实现了 HelloService 服务
	hello_grpc.RegisterHelloServiceServer(s, server)

	fmt.Println("grpc server running :8080") // 打印服务启动信息

	// 启动 gRPC 服务器:开始监听并处理客户端请求(阻塞当前进程)
	err = s.Serve(listen)
	if err != nil { // 若服务启动失败(如端口被占用),打印错误
		grpclog.Fatalf("Failed to serve: %v", err)
	}
}
  • 客户端, 建立 gRPC 客户端与服务端的连接后,通过该连接调用 Protobuf 生成的客户端存根对应的方法,以发起服务请求并获取响应。
package main

import (
	"context"
	"fmt"
	"grpc-study/grpc_proto/hello_grpc"
	"log"

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

func main() {
	address := ":8080"

	// 1. 创建客户端连接选项
	opts := []grpc.DialOption{
		grpc.WithTransportCredentials(insecure.NewCredentials()), // 非安全连接(测试用)
	}

	// 2. 使用 NewClient 创建客户端连接
	conn, err := grpc.NewClient(address, opts...)
	if err != nil {
		log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", address, err))
	}
	defer conn.Close()

	// 3. 创建客户端并调用方法
	client := hello_grpc.NewHelloServiceClient(conn)
	result, err := client.SayHello(context.Background(), &hello_grpc.HelloRequest{
		Name:    "Client",
		Message: "OK",
	})

	fmt.Println(result, err)
}

proto文件

  • 一个proto文件存在多个服务
syntax = "proto3"; // 指定proto版本
// 指定golang包名
option go_package = "/more_proto";

service VideoService {
  rpc Look(Request)returns(Response){}
}

message Request{
  string name = 1;
}
message Response{
  string name = 1;
}


service OrderService {
  rpc Buy(Request)returns(Response){}
}
  • 服务端
package main

import (
	"context"
	"fmt"
	"grpc-study/grpc_proto/more_proto"
	"log"
	"net"

	"google.golang.org/grpc"
)

type VideoServer struct {
	more_proto.UnimplementedVideoServiceServer
}

func (VideoServer) Look(ctx context.Context, request *more_proto.Request) (res *more_proto.Response, err error) {
	fmt.Println("video:", request)
	return &more_proto.Response{
		Name: "Video_Server",
	}, nil
}

type OrderServer struct {
	more_proto.UnimplementedOrderServiceServer
}

func (OrderServer) Buy(ctx context.Context, request *more_proto.Request) (res *more_proto.Response, err error) {
	fmt.Println("order:", request)
	return &more_proto.Response{
		Name: "Order_Server",
	}, nil
}

func main() {
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatal(err)
	}
	s := grpc.NewServer()
	more_proto.RegisterVideoServiceServer(s, &VideoServer{})
	more_proto.RegisterOrderServiceServer(s, &OrderServer{})
	fmt.Println("grpc server程序运行在:8080")
	err = s.Serve(listen)
}
  • 客户端
package main

import (
	"context"
	"fmt"
	"grpc-study/grpc_proto/more_proto"
	"log"

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

func main() {
	addr := ":8080"

	// 1. 创建客户端连接选项
	opts := []grpc.DialOption{
		grpc.WithTransportCredentials(insecure.NewCredentials()), // 非安全连接(测试用)
	}

	// 2. 使用 NewClient 创建客户端连接
	conn, err := grpc.NewClient(addr, opts...)
	if err != nil {
		log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))
	}
	defer conn.Close()

	orderClient := more_proto.NewOrderServiceClient(conn)
	res, err := orderClient.Buy(context.Background(), &more_proto.Request{
		Name: "orderClient",
	})
	fmt.Println(res, err)

	videoClient := more_proto.NewVideoServiceClient(conn)
	res, err = videoClient.Look(context.Background(), &more_proto.Request{
		Name: "videoClient",
	})
	fmt.Println(res, err)

}

流式传输