golang使用grpc

介绍

rpc是一种远程调用协议,在微服务框架中经常使用。其内部也是走的tcp协议,在数据传输过程中也根据数据序列化的不同分化不同数据传输的api比如jsonrpc,grpc。
grpc是使用protocol buffers作为接口定义语言(IDL)和底层数据交换的格式。它可以通过可插拔的支持来有效地连接数据中心内和跨数据中心的服务,以实现负载平衡,跟踪,运行状况检查和身份验证。另外,通过protobuf可以将数据序列化为二进制编码,这会大幅减少需要传输的数据量,从而大幅提高性能

protoc

用protoc生成grpc服务端的代码protocol buffers 在上一节已经介绍了安装教程。linux安装protoc
protobuf语言基础
然后编写test.proto文件用来定义服务以及服务中的方法。这里的实例也是对照 golan中文网

//语法声明 新版本就是proto3 老版本有proto2  proto1
syntax = "proto3";  

package pd; //包名一定要

// 定以  Greeter 微服务
service Greeter {
  // 定义sanHello方法
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// Xiukangr 微服务 (这里定义的服务会生成同名的接口 XiukangrServer,在业务代码中需要实现该接口,然后注册该服务)
service Xiukangr{
  rpc SayXiukang(HelloRequest)  returns (HelloReply) {}
  rpc SayTest(HelloRequest)  returns (HelloReply) {}
}

// HelloRequest 请求数据格式
message HelloRequest {
  string name = 1;
}

// HelloReply 响应数据格式
message HelloReply {
  string message = 1;
}

在以上的test.proto中定义了两个服务,每个服务中有相应方法,另外请求数据格式响应数据格式也已经定义好,在实际的过程中服务结构可能会更加的复杂。
定义好了就要生存相应的go文件了 ,protoc是真的强大,能生成go php c++等十几种语言的相应代码。

protoc -I=./ test.proto --go_out=plugins=grpc:.
# -I 是proto的输入文件路径 如果需要单独生成某个文件的相应代码需要单独填文件名,比如上面的test.proto  
#     如果需要全部的文件那就  -I=./*
# --go_out 这是要输出生成的go服务文件路径 ,java_out那就是java的代码 其他语言依次类推。
#  因为本代码中有rpc的服务所以在输出时一定要带上prlugin=grpc 这句话,生成的代码中将不能实用该服务    

上面的注释中有相应的重点需要铭记不然会有坑。

在运行中可能大部分人会遇到报错如下在这里插入图片描述
这是因为go中缺少protoc-gen-to这个包,需要安装一下。

go get -u github.com/golang/protobuf/protoc-gen-go
  1. 如果下载很慢的话,需要修改go的代理或者实用go mod安装,
  2. 也可以直接通通过迅雷下载到本地然后使用 go install 安装一下就好。需要注意一下安装的路径

生成代码

生成的test.pd.go 代码如下

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: test.proto

package pd

import (
	context "context"
	fmt "fmt"
	proto "github.com/golang/protobuf/proto"
	grpc "google.golang.org/grpc"
	codes "google.golang.org/grpc/codes"
	status "google.golang.org/grpc/status"
	math "math"
)


func (m *HelloRequest) Reset()         { *m = HelloRequest{} }
func (m *HelloRequest) String() string { return proto.CompactTextString(m) }
func (*HelloRequest) ProtoMessage()    {}
func (*HelloRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_c161fcfdc0c3ff1e, []int{0}
}

// HelloReply 响应数据格式
type HelloReply struct {
	Message              string   `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *HelloReply) Reset()         { *m = HelloReply{} }
func (m *HelloReply) String() string { return proto.CompactTextString(m) }
func (*HelloReply) ProtoMessage()    {}
func (*HelloReply) Descriptor() ([]byte, []int) {
	return fileDescriptor_c161fcfdc0c3ff1e, []int{1}
}

func init() {
	proto.RegisterType((*HelloRequest)(nil), "pd.HelloRequest")
	proto.RegisterType((*HelloReply)(nil), "pd.HelloReply")
}

func init() { proto.RegisterFile("test.proto", fileDescriptor_c161fcfdc0c3ff1e) }

var _ context.Context
var _ grpc.ClientConnInterface

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6

// GreeterClient is the client API for Greeter service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type GreeterClient interface {
	// Sends a greeting
	SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
}

type greeterClient struct {
	cc grpc.ClientConnInterface
}

func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {
	return &greeterClient{cc}
}

func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
	out := new(HelloReply)
	err := c.cc.Invoke(ctx, "/pd.Greeter/SayHello", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// GreeterServer is the server API for Greeter service.
type GreeterServer interface {
	// Sends a greeting
	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
}

func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
	s.RegisterService(&_Greeter_serviceDesc, srv)
}

核心的代码主要是生成的 Server和对应的Client相关的代码主要是注册服务,创建客服端相关,另外还有每个服务下的方法的注册和定义描述,剩下就是protobuf序列话相关的东西,代码很多就没有依次贴出来,读者需要细心阅读全部的代码

使用

上面已经生成了相应的服务端和客户端的代码,只需要在服务端直接使用相关方法和实现相应的接口即可。

服务
package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
	pd "grpc/pd"
	"log"
	"net"
)

const (
	port = ":50051"
)

// 1.定义服务
type server struct{}        //服务对象
type xiukangServer struct{} //服务对象

// 2.实现服务的方法
// SayHello 实现服务的接口 在proto中定义的所有服务都是接口
func (s *server) SayHello(ctx context.Context, in *pd.HelloRequest) (*pd.HelloReply, error) {
	fmt.Println("request: ", in.Name)
	return &pd.HelloReply{Message: "Hello " + in.Name}, nil
}

func (xiu *xiukangServer) SayXiukang(ctx context.Context, in *pd.HelloRequest) (*pd.HelloReply, error) {
	fmt.Println("request: ", in.Name)
	return &pd.HelloReply{Message: "Hello xiukang:" + in.Name}, nil
}

func main() {
	lis, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer() //起一个服务

	// 3.注册服务
	pd.RegisterGreeterServer(s, &server{})
	pd.RegisterXiukangrServer(s, &xiukangServer{})
	// 注册反射服务 这个服务是CLI使用的 跟服务本身没有关系
	reflection.Register(s)
	log.Println("rpc服务已经开启 0.0.0.0:50051")
	// 服务监听阻塞中若需要结合其他的服务(如  gin,beego)则需要将本断代码使用在协程中
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
	
}

上面代码的注释中已经讲了过程,首先需要启动一tcp服务,然后定义和实现test.proto中生成的服务接口,然后再注册服务,这里和jsonrpc的方式是一样的,每个服务都需要单独注册。

客服端

客服端代码 /client.go代码如下

/*
@Time : 2020/8/21 下午10:52
@Author : xiukang
@File : client
@Software: GoLand
*/
package grpc

import (
	"context"
	"ginweb/runtime"
	"ginweb/service/grpc/pd"
	"google.golang.org/grpc"
	"log"
	"os"
	"time"
)

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

func StartGrpc() {
	// 1.建立链接
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	// 2.获取相应服务的连接
	greeter := pd.NewGreeterClient(conn)
	xiukang := pd.NewXiukangrClient(conn)
	// Contact the server and print out its response.
	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[1]
	}
	// 1秒的上下文
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := greeter.SayHello(ctx, &pd.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.Message)

	r, err = xiukang.SayXiukang(ctx, &pd.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.Message)
	runtime.Info.Println("grpc service start at 0.0.0.0:50051")
}

客户端代码需要提前获取每个service对应的链接 然后请求相应的方法,具体实现效果如下
客户端
在这里插入图片描述
具体的细节还请看细节代码,因为不知道还有什么其他的坑。

致谢

每次的学习和实践离不开各路大神的前车之鉴,才避免了很多的坑,向在代码中奋斗的人致敬。
golang中文网
什么是rpc
rpc官网
什么是grpc

### 回答1: 很高兴为您提供帮助!关于Go语言中的GRPC教程,您可以参考Go官方文档中的GRPC教程:https://grpc.io/docs/tutorials/basic/go/,也可以参考GitHub上的一些开源项目,如https://github.com/grpc/grpc-go。 ### 回答2: GolangGRPC教程是关于如何使用Google开发的gRPC框架来构建高效的分布式系统的指南。GRPC是一种远程过程调用(RPC)框架,主要用于在客户端和服务器之间进行通信。 GolangGRPC教程首先介绍了GRPC的基本概念和原理,例如客户端和服务器之间的通信方式以及如何定义服务和消息。然后,教程详细介绍了如何在Golang中安装和配置GRPC的软件开发工具包,并提供了一些示例代码来说明如何创建GRPC服务器和客户端。 接下来,教程会教你如何使用protobuf(Protocol Buffers)作为GRPC的数据格式,protobuf是一种轻量级且语言无关的数据序列化机制。你将学会如何定义消息和服务接口,以及如何使用protobuf生成Golang的代码。 在教程的后半部分,你将学习如何使用GRPC的不同功能,如流式传输、服务器端流式和客户端流式,以及双向流式。这些功能可以让你更灵活地设计和实现你的分布式系统。 此外,教程还涉及了如何使用拦截器(interceptors)来实现自定义的认证、日志记录和错误处理等功能。你将了解如何在GRPC中实现服务端和客户端的拦截器,并掌握如何在应用程序中使用它们。 最后,教程还会介绍一些关于GRPC的最佳实践,例如如何处理错误、优化性能和处理并发等问题。这些实践可以帮助你在开发和维护GRPC应用程序时更高效和可靠。 总之,GolangGRPC教程提供了一种简单且强大的方式来构建分布式系统,并为你提供了充足的示例代码和实践经验来帮助你理解和应用GRPC框架。无论是初学者还是有经验的开发者,都能受益于这个教程。 ### 回答3: GolangGRPC教程是介绍Go语言中的GRPC框架的教程。GRPC是一种高性能、开源的远程过程调用(RPC)框架,支持多种编程语言,包括Go语言。 在GRPC教程中,首先会介绍GRPC的基本概念和架构。GRPC使用Protocol Buffers(简称Protobuf)作为接口定义语言(IDL),用于定义服务接口和消息格式。它提供了强类型的接口定义和支持多种语言的代码生成工具。通过IDL的定义,可以自动生成客户端和服务器端代码,大大简化了跨服务通信的开发工作。 接下来的教程将详细介绍如何使用GRPC构建客户端和服务器端。通过定义GRPC服务的接口和消息格式,可以方便地在不同的服务之间进行通信。教程会演示如何编写服务器端代码,实现服务接口的具体逻辑,并将其注册到GRPC框架中。同时,还会演示如何编写客户端代码,通过GRPC调用服务器端提供的服务,并处理返回的结果。 GRPC教程还会介绍一些高级特性,例如流式处理、认证和安全性等。流式处理支持客户端流、服务器端流和双向流,可以实现更复杂的通信模式。认证和安全性可以通过TLS/SSL等机制来保护通信的安全性。 在学习GRPC教程时,你将会了解到GRPC的优势和如何使用GRPC来构建可扩展和高性能的分布式系统。通过GRPC,你可以轻松地实现跨语言的服务调用,并利用其丰富的特性来满足不同的业务需求。 总之,GolangGRPC教程是一个很好的学习资源,能够帮助你掌握GRPC框架的基本概念和使用方法,并在实际项目中应用它来构建高效可靠的分布式系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值