简介:
gRPC是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。
环境:
WIN环境下:
GO 版本1.15
其他包的信息为:
github.com/golang/protobuf v1.4.2
golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
golang.org/x/sys v0.0.0-20200915050820-6d893a6b696e // indirect
golang.org/x/text v0.3.3 // indirect
google.golang.org/genproto v0.0.0-20200914193844-75d14daec038 // indirect
google.golang.org/grpc v1.32.0
google.golang.org/protobuf v1.25.0
实践步骤:
1:下载protocbuf编译器
下载地址:https://github.com/google/protobuf/releases
然后选择对应的版本进行下载。
2:解压protocbuf并配置到环境变量
然后配置:D:\code\go\protoc-3.13.0\bin
到 电脑环境变量中。
3:打开cmd,运行protoc --version
成功打印当前版本信息证明安装成功了
4:安装GO下的相关包
新建项目
修改自己模块名称
4.1安装 golang 的proto工具包
go get -u github.com/golang/protobuf/proto
4.2安装 goalng 的proto编译支持
go get -u github.com/golang/protobuf/protoc-gen-go
4.3 安装 gRPC 包
go get -u google.golang.org/grpc
查看安装的依赖包:
5:编写proto文件(中间件文件)并编译
5.1 1.新建proto文件夹,在里面新建Prod.proto文件
syntax = "proto3";// 协议为proto3
package servies; //生成的文件包的存放包名称
// 定义发送请求信息
message ProdRequest{
// 定义发送的参数
// 参数类型 参数名 标识号(不可重复) 1 表示确定顺序
int32 prod_id = 1;
}
// 定义响应信息返回信息
message ProdResponse{
// 定义接收的参数
// 参数类型 参数名 标识号(不可重复)
int32 prod_stock = 1;
}
// 定义我们的服务(可定义多个服务,每个服务可定义多个接口)
service ProdService{
rpc Route (ProdRequest) returns (ProdResponse){};
}
安装显示proto格式文件的插件
对应的项目目录:
5.1 2. 编译Prod.proto文件
D:\code\go\learngrpc>cd pdfiles
D:\code\go\learngrpc\pdfiles>protoc --go_out=plugins=grpc:../servies ./Prod.proto
提示不是
奇葩了,明明已经配置了还是不行!!!但是CMD可以,这样的话,那只能试一试把protoc.exe复制到GO安装目录bin下:
再进行执行命令OK:
D:\code\go\learngrpc\pdfiles>protoc --go_out=plugins=grpc:../servies ./Prod.proto
最终在package servies有对于的GO文件生成,此文件里面有对于的接口是生产,我们后续的服务就基于此接口的来实现对于的服务:
内容是:
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: Prod.proto
package servies
import (
context "context"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// 定义发送请求信息
type ProdRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// 定义发送的参数
// 参数类型 参数名 标识号(不可重复) 1 表示确定顺序
ProdId int32 `protobuf:"varint,1,opt,name=prod_id,json=prodId,proto3" json:"prod_id,omitempty"`
}
func (x *ProdRequest) Reset() {
*x = ProdRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_Prod_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ProdRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProdRequest) ProtoMessage() {}
func (x *ProdRequest) ProtoReflect() protoreflect.Message {
mi := &file_Prod_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProdRequest.ProtoReflect.Descriptor instead.
func (*ProdRequest) Descriptor() ([]byte, []int) {
return file_Prod_proto_rawDescGZIP(), []int{0}
}
func (x *ProdRequest) GetProdId() int32 {
if x != nil {
return x.ProdId
}
return 0
}
// 定义响应信息返回信息
type ProdResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// 定义接收的参数
// 参数类型 参数名 标识号(不可重复)
ProdStock int32 `protobuf:"varint,1,opt,name=prod_stock,json=prodStock,proto3" json:"prod_stock,omitempty"`
}
func (x *ProdResponse) Reset() {
*x = ProdResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_Prod_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ProdResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProdResponse) ProtoMessage() {}
func (x *ProdResponse) ProtoReflect() protoreflect.Message {
mi := &file_Prod_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProdResponse.ProtoReflect.Descriptor instead.
func (*ProdResponse) Descriptor() ([]byte, []int) {
return file_Prod_proto_rawDescGZIP(), []int{1}
}
func (x *ProdResponse) GetProdStock() int32 {
if x != nil {
return x.ProdStock
}
return 0
}
var File_Prod_proto protoreflect.FileDescriptor
var file_Prod_proto_rawDesc = []byte{
0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x73, 0x65,
0x72, 0x76, 0x69, 0x65, 0x73, 0x22, 0x26, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x64, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x64, 0x49, 0x64, 0x22, 0x2d, 0x0a,
0x0c, 0x50, 0x72, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a,
0x0a, 0x70, 0x72, 0x6f, 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
0x05, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x32, 0x45, 0x0a, 0x0b,
0x50, 0x72, 0x6f, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x52,
0x6f, 0x75, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x65, 0x73, 0x2e, 0x50,
0x72, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x73, 0x65, 0x72,
0x76, 0x69, 0x65, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_Prod_proto_rawDescOnce sync.Once
file_Prod_proto_rawDescData = file_Prod_proto_rawDesc
)
func file_Prod_proto_rawDescGZIP() []byte {
file_Prod_proto_rawDescOnce.Do(func() {
file_Prod_proto_rawDescData = protoimpl.X.CompressGZIP(file_Prod_proto_rawDescData)
})
return file_Prod_proto_rawDescData
}
var file_Prod_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_Prod_proto_goTypes = []interface{}{
(*ProdRequest)(nil), // 0: servies.ProdRequest
(*ProdResponse)(nil), // 1: servies.ProdResponse
}
var file_Prod_proto_depIdxs = []int32{
0, // 0: servies.ProdService.Route:input_type -> servies.ProdRequest
1, // 1: servies.ProdService.Route:output_type -> servies.ProdResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_Prod_proto_init() }
func file_Prod_proto_init() {
if File_Prod_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_Prod_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ProdRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_Prod_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ProdResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_Prod_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_Prod_proto_goTypes,
DependencyIndexes: file_Prod_proto_depIdxs,
MessageInfos: file_Prod_proto_msgTypes,
}.Build()
File_Prod_proto = out.File
file_Prod_proto_rawDesc = nil
file_Prod_proto_goTypes = nil
file_Prod_proto_depIdxs = nil
}
// Reference imports to suppress errors if they are not otherwise used.
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
// ProdServiceClient is the client API for ProdService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type ProdServiceClient interface {
Route(ctx context.Context, in *ProdRequest, opts ...grpc.CallOption) (*ProdResponse, error)
}
type prodServiceClient struct {
cc grpc.ClientConnInterface
}
func NewProdServiceClient(cc grpc.ClientConnInterface) ProdServiceClient {
return &prodServiceClient{cc}
}
func (c *prodServiceClient) Route(ctx context.Context, in *ProdRequest, opts ...grpc.CallOption) (*ProdResponse, error) {
out := new(ProdResponse)
err := c.cc.Invoke(ctx, "/servies.ProdService/Route", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ProdServiceServer is the server API for ProdService service.
type ProdServiceServer interface {
Route(context.Context, *ProdRequest) (*ProdResponse, error)
}
// UnimplementedProdServiceServer can be embedded to have forward compatible implementations.
type UnimplementedProdServiceServer struct {
}
func (*UnimplementedProdServiceServer) Route(context.Context, *ProdRequest) (*ProdResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Route not implemented")
}
func RegisterProdServiceServer(s *grpc.Server, srv ProdServiceServer) {
s.RegisterService(&_ProdService_serviceDesc, srv)
}
func _ProdService_Route_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProdRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProdServiceServer).Route(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/servies.ProdService/Route",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProdServiceServer).Route(ctx, req.(*ProdRequest))
}
return interceptor(ctx, in, info, handler)
}
var _ProdService_serviceDesc = grpc.ServiceDesc{
ServiceName: "servies.ProdService",
HandlerType: (*ProdServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Route",
Handler: _ProdService_Route_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "Prod.proto",
}
6:生成对应的服务实现相关生成的接口的文件信息
实现ProdServiceClient接口的方法:
type ProdServiceClient interface {
Route(ctx context.Context, in *ProdRequest, opts ...grpc.CallOption) (*ProdResponse, error)
}
实现内容:
返回的是一个指针类型的
package servies
import (
"context"
)
// 定义我们的服务
type ProdServies struct{}
//func (this *ProdServies)GetProdStock(ctx context.Context, request *ProdRequest, opts ...grpc.CallOption) (*ProdResponse, error) {
// return &ProdResponse{ProdStock: 20},nil
//}
// Route 实现Route方法
func (s *ProdServies) Route(ctx context.Context, req *ProdRequest) (*ProdResponse, error) {
res := ProdResponse{ProdStock:req.ProdId}
return &res, nil
}
7:创建服务端-新建一个server.go
注册的服务是基于上次生产的GO文件里面的
func RegisterProdServiceServer(s *grpc.Server, srv ProdServiceServer) {
s.RegisterService(&_ProdService_serviceDesc, srv)
}
正式的内容信息为:
package main
import (
"google.golang.org/grpc"
"log"
"net"
"xiaozhong/servies"
)
func main() {
// 监听本地端口// Address 监听地址// Network 网络通信协议
listener, err := net.Listen("tcp", ":8000")
if err != nil {
log.Fatalf("net.Listen err: %v", err)
}
log.Println(" net.Listing...8000")
// 新建gRPC服务器实例
grpcServer := grpc.NewServer()
// 在gRPC服务器注册我们的服务
servies.RegisterProdServiceServer(grpcServer, &servies.ProdServies{})
//用服务器 Serve() 方法以及我们的端口信息区实现阻塞等待,直到进程被杀死或者 Stop() 被调用
err = grpcServer.Serve(listener)
if err != nil {
log.Fatalf("grpcServer.Serve err: %v", err)
}
}
启动服务端:
看到启动信息为:
8:创建客户端client.go,访问服务端调用接口 获取信息-
package main
import (
"context"
"google.golang.org/grpc"
"log"
"xiaozhong/servies"
)
const (
// Address 连接地址
Address string = ":8000"
)
func main() {
// 连接服务器
conn, err := grpc.Dial(Address, grpc.WithInsecure())
if err != nil {
log.Fatalf("net.Connect err: %v", err)
}
defer conn.Close()
// 建立gRPC连接
grpcClient := servies.NewProdServiceClient(conn)
// 创建发送结构体
req := servies.ProdRequest{
ProdId: 15555,
}
// 调用我们的服务(Route方法)
// 同时传入了一个 context.Context ,在有需要时可以让我们改变RPC的行为,比如超时/取消一个正在运行的RPC
res, err := grpcClient.Route(context.Background(), &req)
if err != nil {
log.Fatalf("Call Route err: %v", err)
}
// 打印返回值
log.Println(res)
}
运行的我们客户端:
PS:成功调用服务端的Server端的Route方法并获取返回我们自己传输的数据参数值。
最终的项目目录结构是:
有疑问加站长微信联系(非本文作者)