Golang GRPC简单使用

Posted Time-Traveler

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang GRPC简单使用相关的知识,希望对你有一定的参考价值。


什么是GRPC?

rpc框架一般基于tcp或者http协议实现。基于http的rpc框架有许多优点,HTTP/1.x协议简单明了,是目前最流行的应用层协议,有着非常成熟且完善的各种基础设施,如负载均衡、监控、代理等,适用性广泛,各个设备系统均有实现。但是缺点也很明显,就是HTTP/1.x采用的是文本协议,解析速度慢,带宽占用高。而且request/response的通信方法导致整体效率不高。gRPC基于HTTP2协议,HTTP2 使得grpc 能够更好的适用于移动客户端和服务端通信的使用场景,并且连接多路复用也保证了RPC 的效率。grpc 的协议设计上很好的使用了HTTP2 现有的语义,请求和响应的数据使用HTTP Body 发送,其他的控制信息则用Header 表示。

图片来自网络,从上图和文档中我们可以了解到,用gRPC来进行远程服务调用就仅仅需要gRPC Stub(Client)用Proto Request向远方的gRPC Server发起服务调用,然后远方的gRPC Server通过Proto Response(s)将调用结果返回给gRPC Stub。
话不多说,在上代码之前,贴出项目最终的一个样子!

好,接下来我们还有一些东西需要提前准备,protoc.exe 以及protoc-gen-go.exe两个工具:

  1. protoc.exe直接下载就好了(传送门)
  2. protoc-gen-go这个需要安装依赖(需要将其放到环境变量中):
     go get github.com/golang/protobuf/protoc-gen-go
    

接下来就到了代码环节了。

创建proto文件:

syntax = "proto3";
package services;

option go_package = "./protos;protos";

// 定义发送请求信息
message UserRequest{
  // 定义发送的参数
  // 参数类型 参数名 标识号(不可重复) 1  表示确定顺序
  string  user_id = 1;
}

// 定义响应信息返回信息
message UserResponse{
  string user_id = 1;
  int32 score = 2;
  int32 age = 3;
  string user_name = 4;
}

service UserService{
  rpc GetUserInfo (UserRequest) returns (UserResponse){};
}

Protobuf生成Go代码指南:https://juejin.cn/post/6844903944511029262
编译proto文件:

.\\protoc.exe --go_out=plugins=grpc:. .\\protos\\user.proto

protoc.exe是在与main.go同一级目录下的,我这是没有放在环境变量中的情况,使用的时候需要注意相对路径。
编译完成后则会在protos文件夹下新增一个user.pb.go文件。里面有很多东西我们先不用管,只需要先实现我们定义的rpc方法。

服务端(main.go):

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	pb "grpcserver/protos"
	"log"
	"net"
)

const DefaultUserId = "11111"

var userMap = map[string]User{
	DefaultUserId: {
		UserId:   DefaultUserId,
		UserName: "user_name_1",
		Score:    101,
		Age:      10,
	},
}

type UserInfoService struct{}

type User struct {
	UserId   string
	UserName string
	Score    int32
	Age      int32
}

func (c *UserInfoService) GetUserInfo(ctx context.Context, in *pb.UserRequest) (*pb.UserResponse, error) {
	response := new(pb.UserResponse)
	userId := in.GetUserId()
	fmt.Println("user_id: ", userId)
	if userId != "" {
		user, ok := userMap[userId]
		if ok{
			response.UserId = user.UserId
			response.UserName = user.UserName
			response.Age = user.Age
			response.Score = user.Score
		}
	}
	return response, nil
}

func main() {
	// 监听本地端口// Address 监听地址// Network 网络通信协议
	listener, err := net.Listen("tcp", ":8000")
	if err != nil {
		log.Fatalf("net.Listen err: %v", err)
	}

	server := grpc.NewServer()
	// 在gRPC服务器注册我们的服务
	pb.RegisterUserServiceServer(server, &UserInfoService{})

	err = server.Serve(listener)
	if err != nil {
		log.Fatalf("server err: %v", err)
	}
}

客户端(client.go):

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	pb "grpcserver/protos"
	"log"
)


const (
	Address = ":8000"
)

func main() {
	// 连接服务器
	conn, err := grpc.Dial(Address, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("grpc dail err: %v", err)
		return
	}
	defer conn.Close()

	client := pb.NewUserServiceClient(conn)
	// 创建发送结构体
	req := pb.UserRequest{
		UserId: "11111",
	}
	// 调用我们的服务(GetUserInfo方法)
	// 同时传入了一个 context.Context ,在有需要时可以让我们改变GRPC的行为,比如超时/取消一个正在运行的RPC
	res, err := client.GetUserInfo(context.Background(), &req)
	if err != nil {
		log.Fatalf("call getUserInfo err: %v", err)
		return
	}

	fmt.Println(res)
}

先启动服务端,然后在启动客户端,最终结果如下:

以上是关于Golang GRPC简单使用的主要内容,如果未能解决你的问题,请参考以下文章

Golang GRPC简单使用

Golang GRPC简单使用

Golang GRPC简单使用

grpc的简单用例 (golang实现)

grpc之golang学习笔记2

代码片段 - Golang 实现简单的 Web 服务器