gRPC支持四种类型的方法,分别是:

  • Unary模式
  • 客户端流模式
  • 服务端流模式
  • 双向流模式

其中最常见的是Unary模式(即一元模式),我们在本章节仅介绍Unary模式。

Unary模式,也可以称为“一问一答模式”,客户端发送一个请求给服务端,服务端返回一个响应,和一次普通的函数调用类似。
示意图如下:

gRPC一元模式

下面我们来实现一个简单的Unary接口。

要通过grpc提供接口,可以分为以下三个步骤:

  • 接口定义(.proto文件)。
  • 生成相关代码。
  • 服务端开发。
  • 客户端开发。

接口定义

我们这里实现一个简单的greet功能,项目目录结构如下:

proto 存放proto文件。
pb 存放生成的go文件。
server 服务端代码。
client 客户端代码。
bin 可执行文件。

proto文件定义如下(greet.proto):

syntax = "proto3";

package proto;

option go_package = "git.gqnotes.com/guoqiang/grpcexercises/greet/pb";

service GreetService {
  rpc Greet(GreetRequest) returns(GreetResponse) {}
}

message GreetRequest {
  string greeting = 1;
}


message GreetResponse {
  string result = 1;
}

定义Makefile,方便执行相关操作:

tidy:
    go mod tidy

greet-gen:
     protoc -Igreet/proto/ --go_out=./greet --go_opt=module=git.gqnotes.com/guoqiang/grpcexercises/greet --go-grpc_out=./greet --go-grpc_opt=module=git.gqnotes.com/guoqiang/grpcexercises/greet greet/proto/*.proto

greet-build:
     go build -o ./greet/bin/server-osx ./greet/server
     go build -o ./greet/bin/client-osx ./greet/client

.PHONY: tidy greet-gen greet-build

生成相关代码

在项目目录(greet上级目录)下执行如命令:

make greet-gen

执行成功,在pb目录下生成相关文件。

服务端开发

在server目录下添加两个文件:

  • main.go,服务入口文件。
  • Greet.go,Greet方法实现。

代码如下:
<details>
<summary>main.go</summary>

package main

import (
    "git.gqnotes.com/guoqiang/grpcexercises/greet/pb"
    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
    "log"
    "net"
)

func main() {
    // 实现服务端逻辑,监听5632端口
    lis, err := net.Listen("tcp", ":5632")

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

    s := grpc.NewServer()

    // 注册服务
    pb.RegisterGreetServiceServer(s, &Server{})

    reflection.Register(s)

    log.Println("grpc server start")

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

type Server struct {
    pb.UnimplementedGreetServiceServer
}

</details>

<details>
<summary>Greet.go</summary>

package main

import (
    "context"
    "git.gqnotes.com/guoqiang/grpcexercises/greet/pb"
    "log"
    "time"
)

// Greet greet
func (s *Server) Greet(ctx context.Context, req *pb.GreetRequest) (*pb.GreetResponse, error) {
    log.Printf("Greet function was invoked with %v\n", req)

    result := "Hello " + req.GetGreeting() + ", now time is:" + time.Now().String()

    res := &pb.GreetResponse{
        Result: result,
    }

    return res, nil
}

</details>

客户端开发

在client目录下添加客户端代码,有两个文件:

  • main.go,程序入口文件。
  • Greet.go,具体方法文件。

文件内容如下:
<details>
<summary>main.go</summary>

package main

import (
    "git.gqnotes.com/guoqiang/grpcexercises/greet/pb"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    "log"
)

func main() {
    conn, err := grpc.Dial(":5632", grpc.WithTransportCredentials(insecure.NewCredentials()))

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

    defer conn.Close()

    // 实例化客户端
    client := pb.NewGreetServiceClient(conn)

    // 调用方法
    Greet(client)
}

</details>

<details>
<summary>Greet.go</summary>

package main

import (
    "context"
    "git.gqnotes.com/guoqiang/grpcexercises/greet/pb"
    "log"
)

func Greet(client pb.GreetServiceClient) {
    response, err := client.Greet(context.Background(), &pb.GreetRequest{
        Greeting: "xiaoming",
    })

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

    log.Printf("response:%+v\n", response)
}

</details>

执行

在项目目录下执行make tidy,拉取相关库,然后执行 make greet-build,生成可执行文件。
然后在命令行下执行如下命令,启动服务端程序:

./greet/bin/server-osx

执行如下命令,测试客户端文件:

./greet/bin/client-osx

执行结果如下:

2023/12/02 15:02:26 response:result:"Hello xiaoming now time is:2023-12-02 15:02:26.443767 +0800 CST m=+1268.825308543"

代码地址

本文由mdnice多平台发布


guoqiang
1 声望0 粉丝

从事开发工作多年,使用过php和golang,目前主要使用golang开发后端服务。