1.新建项目

practice
│  ├─go.mod
│  │   ├─go.sum
│  ├─api
│  │  ├─api.proto
│  │  └─pb
│  │      └─api.pb.go
│  │      └─api_grpc.pb.go
│  ├─client
│  │  ├─client.go
│  └─server
│     ├─server.go

2、项目初始化

$ cd practice
$ go mod init

3.定义一个proto例子api.proto

syntax = "proto3";
package api;

service ProductInfo {
  // 添加商品
  rpc addProduct(Product) returns (ProductId);
  // 获取商品
  rpc getProduct(ProductId) returns (Product);
}

message Product {
  string id = 1;
  string name = 2;
  string description = 3;
}

message ProductId {
  string value = 1;
}

4.编译proto文件,生成go代码

$ cd api
$ protoc --go_out=. --go-grpc_out=. api.proto

会生成两个文件,将这两个文件移动到 practice/api/pb目录下
practice
│  ├─api
│  │  ├─api.proto
│  │  └─pb
│  │      └─api.pb.go
│  │      └─api_grpc.pb.go

5、客户端程序代码如下 client.go

package main

import (
	"context"
	"flag"
	"google.golang.org/grpc"
	"log"
	pb "practice/api/pb"
	"time"
)

const (
	defaultId = "1"
)

var (
	addr = flag.String("addr", "localhost:50051", "the address to connect to")
	id   = flag.String("id", defaultId, "product to greet")
)

// 此方法仅以获取商品举例说明 getProduct()
func main() {
	flag.Parse()

	// 建立连接
	conn, err := grpc.Dial(*addr, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	// 实例化client
	c := pb.NewProductInfoClient(conn)

	// 调用rpc,等待同步响应
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	// 1、客户端函数调用,返回商品信息Product
	r, err := c.GetProduct(ctx, &pb.ProductId{Id: *id})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	// 打印商品信息
	log.Printf("Id: %s", r.GetId())
	log.Printf("Name: %s", r.GetName())
	log.Printf("Description: %s", r.GetDescription())

}

6、服务端程序代码如下 server.go

package main

import (
	"context"
	"flag"
	"fmt"
	"google.golang.org/grpc"
	"log"
	"net"
	pb "practice/api/pb"
)

var (
	port = flag.Int("port", 50051, "The server port")
)

// server is used to implement helloworld.GreeterServer.
type server struct {
	pb.UnimplementedProductInfoServer
}

// 2、服务端函数定义(客户端传进来Id)
func (s *server) GetProduct(ctx context.Context, in *pb.ProductId) (*pb.Product, error) {
	return &pb.Product{Id: in.Id, Name: "巧克力", Description: "俄罗斯黑巧克力100%浓度"}, nil
}

func main() {
	flag.Parse()
	// 监听端口
	lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	// 实例化server
	s := grpc.NewServer()
	pb.RegisterProductInfoServer(s, &server{})
	log.Printf("server listening at %v", lis.Addr())
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

7、运行

启动服务端

$ go run server.go
2022/06/08 17:06:12 server listening at 127.0.0.1:50051

启动客户端

$ go run client.go
2022/06/08 17:06:17 Id: 1
2022/06/08 17:06:17 Name: 巧克力
2022/06/08 17:06:17 Description: 俄罗斯黑巧克力100%浓度

8、完成

项目源代码:点击下载