9、gRPC


 之前 protobuf 时安装过,不需安装

快速开启 grpc 服务

新建目录 testGrpc 。以及 testGrpc/service 和 testGrpc/client

testGrpc 下新建 hello.proto

syntax = "proto3";

package tempPackageName;

option go_package = "ginStart/testGrpc/service/helloPackage"; // 生成在service文件夹下,包名为 helloPackage

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}


// 生成普通结构文件
// protoc --go_out=client --go_opt=paths=source_relative grpc.proto

// 生成 grpc 文件
// protoc --go-grpc_out=service --go-grpc_opt=paths=source_relative grpc.proto // 若是 . 表示当前目录
// --go-grpc_out=service // 定义输出路径
// --go-grpc_opt=paths=source_relative // 定义输入路径
// grpc.proto // 定义需要编译的文件

// 两种文件一起生成
// protoc --go_out=. --go_opt=paths=source_relative \
// --go-grpc_out=. --go-grpc_opt=paths=source_relative \
// grpc.proto

执行命令在当前文件夹生成文件

 protoc --go_out=. --go_opt=paths=source_relative \
 --go-grpc_out=. --go-grpc_opt=paths=source_relative \
 grpc.proto

在 service 下新建 main.go

package main

import (
    "context"
    "google.golang.org/grpc"
    "log"
    "net"
    pb "project/testGrpc"
)

// 在 hello_grpc.pb.go 里面找到 GreeterServer 接口
//type GreeterServer interface {
//    // Sends a greeting
//    SayHello(context.Context, *HelloRequest) (*HelloReply, error)
//    mustEmbedUnimplementedGreeterServer()
//}

// 根据格式,实现接口

// server is used to implement hello.GreeterServer.
type server struct {
    pb.UnimplementedGreeterServer
}

// SayHello implements hello.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    //log.Printf("Received: %v", in.GetName())

    return &pb.HelloReply{
        Message: "Hello " + in.GetName(),
    }, nil
}


func main() {

    // 监听 tcp 的 50051 端口
    lis, err := net.Listen("tcp", "localhost:50051")
    if err != nil {
        log.Fatalf("failed to listen: %v", err) // 监听发生错误就打印出来,随后退出
    }

    // 初始化服务
    s := grpc.NewServer()

    // 注册服务
    pb.RegisterGreeterServer(s, &server{})

    log.Printf("server listening at %v", lis.Addr()) // 一些无关紧要的打印信息

    // 开启服务
    err = s.Serve(lis)

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

启动服务端

go run service/main.go

在 client 下新建main.go

package main

import (
    "context"
    "google.golang.org/grpc"
    "log"
    pb "project/testGrpc"
    "time"
)

func main() {

    // 开始请求服务端
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }

    // 请求结束后就自动关闭连接
    defer conn.Close()

    // 初始化客户端连接
    c := pb.NewGreeterClient(conn)

    // Contact the server and print out its response.
    //name := defaultName
    //if len(os.Args) > 1 {
    //    name = os.Args[1]
    //}

    // 创建一个子节点的context,1秒后自动超时
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()

    // 发送请求体,返回内容
    r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "好家伙"})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }

    log.Printf("Greeting: %s", r.GetMessage())
}

客户端开始连接测试

go run client/main.go

GRPC Gateway 实现

在主目录新建 hello.yaml

type: google.api.Service

config_version: 3

http:
  rules:
    - selector: tempPackageName.Greeter.SayHello
      get: /haha/{name}

创建 .bat 快捷键 (最后一行是生成gateway)

protoc --go_out=. --go_opt=paths=source_relative hello.proto
protoc --go-grpc_out=. --go-grpc_opt=paths=source_relative  hello.proto
protoc --grpc-gateway_out=. --grpc-gateway_opt=paths=source_relative,grpc_api_configuration=hello.yaml hello.proto

调用生成

./gen.bat

在 service/main.go 里面

package main

import (
    "context"
    "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    "google.golang.org/grpc"
    "log"
    "net"
    "net/http"
    pb "project/testGrpc"
)

type server struct {
    pb.UnimplementedGreeterServer
}

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {

    return &pb.HelloReply{
        Message: "Hello "+ in.GetName(),
    }, nil
}


func main() {
    // 新增 grpc gateway
    go grpcGateWay()

    // 监听 tcp 的 8088 端口
    lis, err := net.Listen("tcp", "localhost:50051")
    if err != nil {
        log.Fatalf("failed to listen: %v", err) // 监听发生错误就打印出来,随后退出
    }

    // 初始化服务
    s := grpc.NewServer()

    // 注册服务
    pb.RegisterGreeterServer(s, &server{})

    log.Printf("server listening at %v", lis.Addr()) // 一些无关紧要的打印信息

    // 开启服务
    err = s.Serve(lis)

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

func grpcGateWay() {
    // 生成没有具体内容的上下文
    c := context.Background()

    // 给它新增退出功能
    c, cancel := context.WithCancel(c)
    defer cancel()

    mux := runtime.NewServeMux()

    // 注册 grpc 服务
    err := pb.RegisterGreeterHandlerFromEndpoint(
        c,
        mux,
        ":50051",
        []grpc.DialOption{grpc.WithInsecure()},
    )

    if err != nil {
        log.Fatalf("can not start grpc gateway:%v",err)
    }

    // 监听端口中的 HTTP 请求,监听到就按照 .yaml 的内容进行分发
    err = http.ListenAndServe(":8080",mux)

    if err != nil {
        log.Fatalf("can not start grpc gateway:%v",err)
    }
}

起服务后,浏览器访问

相关