grpc入门 | 青训营

145 阅读3分钟

当谈到gRPC和Go语言的结合时,我们探讨的是如何在Go中使用gRPC框架来实现高效的远程过程调用。下面将详细介绍gRPC在Go语言中的安装、原生RPC、一个简单的gRPC示例、Proto文件定义、以及gRPC流式传输的相关内容。

1. gRPC 安装

在Go语言中安装gRPC非常简单。你可以使用Go的模块管理工具来获取所需的依赖。

https://github.com/protocolbuffers/protobuf/releases/download/v3.9.0/protoc-3.9.0-win64.zip

// 都需要安装的依赖
go get github.com/golang/protobuf/proto
go get google.golang.org/grpc
go install github.com/golang/protobuf/protoc-gen-go

2. 原生 RPC(Remote Procedure Call)

原生的RPC是gRPC的基础,它允许你在不同的机器上调用远程服务器上的方法。

原生RPC的问题:

  1. 编写相对复杂,需要自己去关注实现过程
  2. 没有代码提示,容易写错

2.1 服务端

package main

import (
  "fmt"
  "net"
  "net/http"
  "net/rpc"
)

type Server struct {
}
type Req struct {
  Num1 int
  Num2 int
}
type Res struct {
  Num int
}

func (s Server) Add(req Req, res *Res) error {
  res.Num = req.Num1 + req.Num2
  return nil
}

func main() {
  // 注册rpc服务
  rpc.Register(new(Server))
  rpc.HandleHTTP()
  listen, err := net.Listen("tcp", ":8080")
  if err != nil {
    fmt.Println(err)
    return
  }
  http.Serve(listen, nil)
}

2.2 客户端

创建一个客户端来调用远程方法。

package main

import (
  "fmt"
  "net/rpc"
)

type Req struct {
  Num1 int
  Num2 int
}
type Res struct {
  Num int
}

func main() {
  req := Req{1, 2}
  client, err := rpc.DialHTTP("tcp", ":8080")
  if err != nil {
    fmt.Println(err)
    return
  }
  var res Res
  client.Call("Server.Add", req, &res)
  fmt.Println(res)
}

3. gRPC 示例

让我们通过一个简单的示例来演示如何在Go中使用gRPC。

3.1 定义 Proto 文件

首先,我们需要定义一个Proto文件,其中包含服务接口和消息类型的定义。

syntax = "proto3";

package helloworld;

service Greeter {
    rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
    string name = 1;
}

message HelloResponse {
    string message = 1;
}

3.2 生成代码

使用protoc编译器生成Go代码:

protoc -I. --go_out=. --go-grpc_out=. helloworld.proto

3.3 服务实现

实现服务接口,这里我们创建一个Greeter服务类来处理客户端请求。

package main

import (
	"context"
	"fmt"
	"net"

	"google.golang.org/grpc"
)

type GreeterServer struct{}

func (s *GreeterServer) SayHello(ctx context.Context, req *HelloRequest) (*HelloResponse, error) {
	message := fmt.Sprintf("Hello, %s!", req.Name)
	return &HelloResponse{Message: message}, nil
}

func main() {
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	grpcServer := grpc.NewServer()
	RegisterGreeterServer(grpcServer, &GreeterServer{})

	err = grpcServer.Serve(listen)
	if err != nil {
		panic(err)
	}
}

3.4 客户端调用

创建一个客户端来调用远程方法。

package main

import (
	"context"
	"fmt"
	"log"

	"google.golang.org/grpc"
)

func main() {
	conn, err := grpc.Dial(":8080", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Dial failed: %v", err)
	}
	defer conn.Close()

	client := NewGreeterClient(conn)

	request := &HelloRequest{Name: "Alice"}
	response, err := client.SayHello(context.Background(), request)
	if err != nil {
		log.Fatalf("Error calling SayHello: %v", err)
	}

	fmt.Printf("Response: %s\n", response.Message)
}

4. Proto 文件详解

Proto 文件定义了gRPC服务的接口、消息类型和服务方法。

4.1 定义消息类型

使用Proto语法定义消息字段和类型。

message MyMessage {
    string name = 1;
    int32 age = 2;
}

4.2 定义服务接口

定义服务方法、输入和输出消息类型。

service MyService {
    rpc MyMethod(MyRequest) returns (MyResponse);
}

4.3 编译 Proto 文件

使用protoc编译器将Proto文件编译成Go语言的代码。

protoc -I. --go_out=. myproto.proto

5. gRPC 流式传输

gRPC支持多种类型的流式传输,包括一对一、一对多和多对多流式传输。

5.1 一对一流式

定义流式请求和响应方法,允许客户端和服务器进行逐个交互。

service MyService {
    rpc MyMethod(stream MyRequest) returns (stream MyResponse);
}

5.2 一对多流式

服务器端可以返回一个流,客户端逐个读取响应。

service MyService {
    rpc MyMethod(MyRequest) returns (stream MyResponse);
}

5.3 多对一流式

客户端发送流式请求,服务器逐个读取请求。

service MyService {
    rpc MyMethod(stream MyRequest) returns (MyResponse);
}

5.4 多对多流式

双方都可以发送和接收流,

实现实时交互。

service MyService {
    rpc MyMethod(stream MyRequest) returns (stream MyResponse);
}

以上是关于gRPC在Go语言中的详细介绍,涵盖了安装、原始RPC、一个示例、Proto文件的定义和gRPC流式传输等方面。通过深入了解这些内容,你可以在教学中帮助学生更好地理解和应用gRPC技术。如有需要进一步了解某个主题,也可以随时联系我。