Grpc实践

实践参考文档

官方grpc小例子分析

目录结构
image.png

helloword.proto

client、server交互的接口定义文件,protoc命令会解析此文件生成对应的接口文件。它就好比是电话簿,记录名字(可以理解为函数名)和它的电话号码(可以理解路由到server具体方法的地址),client就可以根据它来调用server的特定方法。

syntax = "proto3";

option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

package helloworld;

// 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;
}

SayHello是client、server通信的函数,server端定义此函数,client端与server端建立连接后可以直接调用此函数

greeter_server/main.go

package main

import (
	"context"
	"log"
	"net"

	"google.golang.org/grpc"
	pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

const (
	port = ":50051"
)

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

// SayHello implements helloworld.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() {
	lis, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

接口函数SayHello具体的逻辑在server层定义

  1. server结构体继承grpc文件中的结构体UnimplementedGreeterServer (绑定了SayHello方法)
  2. 对server结构体重新定义Sayhello接口
  3. 客户端与server建连后可以直接调用服务层的SayHello方法

greeter_client/main.go

package main

import (
	"context"
	"log"
	"os"
	"time"

	"google.golang.org/grpc"
	pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

const (
	address     = "localhost:50051"
	defaultName = "world"
)

func main() {
	// Set up a connection to the server.
	conn, err := grpc.Dial(address, 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]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.GetMessage())
}
  1. 调用grpc.dial方法与server建立连接
  2. 调用server层的接口函数,这里的调用方式:c.Sayhello

准备环境

# 下载安装包到$GOPATH/google.golang.org/ 下,因为待安装的包导入路径是google.golang.org
git clone https://github.com/protocolbuffers/protobuf-go.git
git clone https://github.com/grpc/grpc-go.git
# 安装,安装完之后生产全局可见的二进制可执行文件
git install google.golang.org/protobuf/cmd/protoc-gen-go
go install google.golang.org/grpc-go/cmd/protoc-gen-go-grpc

编辑protoc文件注意项

  • 文件头部加上go_package选项,如
syntax = "proto3";  f

option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

package helloworld;
  • 如果引用了其他protoc文件中的变量则导入相关文件,如
syntax = "proto3";
// redis-agent在$GOPATH/src下
option go_package = "redis-agent/vendor/tinker/communicator/protobuf";
package protobuf;
import "tinker.proto";

进入protoc文件所在的目录,编译protoc文件,会在当前目录下生成对应的go文件

protoc --go_out=. --go_opt=paths=source_relative     --go-grpc_out=. --go-grpc_opt=paths=source_relative     proxy_agent.proto
  • 确保protoc和grpc包版本对应,否则protoc编译出的$前缀_grpc.go文件可能会遇到方法或变量未定义的问题,如
    image.png
    我这里部署采用的版本如下,下载的都是最新版本的主分支
$ protoc-gen-go --version
protoc-gen-go v1.25.0-devel
$ protoc-gen-go-grpc --version
protoc-gen-go-grpc 1.0.1
$ protoc --version
libprotoc 3.11.4

遇到的问题

  • 调用rpc接口的server文件报异常
    image.png
    报错意思是rpc注册函数agentpb.RegisterProxyAgentServer中的第二个结构体参数定义了mustEmbedUnimplementedProxyAgentServer方法,但是传的&ProxyAgentServer{}参数却没有绑定这种方法。agentpb文件中UnimplementedProxyAgentServer结构体绑定了这种方法
    image.png

所以在server文件中可以通过继承UnimplementedProxyAgentServer结构体的方式来解决,如

# server 文件中ProxyAgentServer结构体继承agentpb.UnimplementedProxyAgentServer
type ProxyAgentServer struct {
	agentpb.UnimplementedProxyAgentServer
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值