gRPC快速入門(四)——gRPC快速入門-創(chuàng)新互聯(lián)

gRPC快速入門(四)——gRPC快速入門

一、gRPC簡介

1、gRPC簡介

gRPC是一個高性能、通用的開源RPC框架,基于ProtoBuf(Protocol Buffers)序列化協(xié)議開發(fā),且支持眾多開發(fā)語言,目前提供C、Java和Go語言版本,分別是grpc、grpc-java、grpc-go。gRPC提供了一種簡單的方法來精確地定義服務(wù)和為iOS、Android和后臺支持服務(wù)自動生成可靠性很強的客戶端功能庫。gRPC基于HTTP/2標(biāo)準(zhǔn)設(shè)計,帶來諸如雙向流、流控、頭部壓縮、單TCP連接上的多復(fù)用請求等特性,使得gRPC在移動設(shè)備上表現(xiàn)更好、更省電和節(jié)省空間占用。

創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供饒平網(wǎng)站建設(shè)、饒平做網(wǎng)站、饒平網(wǎng)站設(shè)計、饒平網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、饒平企業(yè)網(wǎng)站模板建站服務(wù),十余年饒平做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。

2、gRPC的優(yōu)點

gRPC優(yōu)點如下:
(1)平臺無關(guān),語言無關(guān),可擴展;
(2)提供了友好的動態(tài)庫,使用簡單;
(3)解析速度快,比對應(yīng)的XML快約20-100倍;
(4)序列化數(shù)據(jù)非常簡潔、緊湊,與XML相比,其序列化之后的數(shù)據(jù)量約為1/3到1/10。

3、gRPC安裝

官方推薦安裝命令:
go get google.golang.org/grpc
國內(nèi)網(wǎng)絡(luò)環(huán)境由于GFW原因,不能直接訪問google服務(wù)器,報錯如下:
package google.golang.org/grpc: unrecognized import path "google.golang.org/grpc" (https fetch: Get https://google.golang.org/grpc?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)
因此,在國內(nèi)網(wǎng)絡(luò)環(huán)境下推薦直接從GitHub下載相應(yīng)依賴進行安裝。

git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net
git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto
git clone https://github.com/golang/sys $GOPATH/src/golang.org/x/sys

安裝gRPC:
go install google.golang.org/grpc

二、gRPC使用

1、gRPC使用流程

gRPC使用流程如下:
(1)編寫.proto描述文件。
(2)編譯生成.pb.go文件。
(3)服務(wù)端實現(xiàn)約定的接口并提供服務(wù)。
(4)客戶端按照約定調(diào)用方法請求服務(wù)。

2、proto service定義

一個RPC service是一個能夠通過參數(shù)和返回值進行遠程調(diào)用的方法。由于gRPC通過將數(shù)據(jù)編碼成Protocal Buffer來實現(xiàn)傳輸,因此,使用者可以通過Protocal Buffers interface definitioin language(IDL)來定義service method,同時將參數(shù)和返回值也定義成Protocal Buffer message類型。gRPC源碼目錄提供了多個使用示例,本文使用helloworld示例作為模板,helloworld示例目錄位于google.golang.org/grpc/examples/helloworld。
在$GOPATH/src目錄下創(chuàng)建helloworld目錄,包含proto、server、client子目錄。proto目錄下創(chuàng)建helloworld.proto文件。
helloworld.proto:

syntax = "proto3";

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

helloworld.proto文件中定義了一個Greeter Service,服務(wù)包含一個SayHello方法,同時聲明了HelloRequest和HelloReply消息結(jié)構(gòu)用于請求和響應(yīng)??蛻舳耸褂肏elloRequest參數(shù)調(diào)用SayHello方法請求服務(wù)端,服務(wù)端響應(yīng)HelloReply消息。

3、生成Go代碼

根據(jù)定義的RPC service,利用protocal buffer compiler,即protoc生成相應(yīng)的服務(wù)器端和客戶端的Go代碼,生成的代碼中包含了客戶端能夠進行RPC的方法以及服務(wù)器端需要進行實現(xiàn)的接口。
在$GOPATH/src/helloworld/proto目錄下生成gRPC對應(yīng)的Go代碼的命令如下:
protoc --go_out=plugins=grpc:. helloworld.proto
將在目錄下生成helloworld.pb.go文件,內(nèi)容如下:

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

package helloworld

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

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

// The request message containing the user's name.
type HelloRequest struct {
    Name                 string   `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}

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_17b8c58d586b62f2, []int{0}
}

func (m *HelloRequest) XXX_Unmarshal(b []byte) error {
    return xxx_messageInfo_HelloRequest.Unmarshal(m, b)
}
func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
    return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic)
}
func (m *HelloRequest) XXX_Merge(src proto.Message) {
    xxx_messageInfo_HelloRequest.Merge(m, src)
}
func (m *HelloRequest) XXX_Size() int {
    return xxx_messageInfo_HelloRequest.Size(m)
}
func (m *HelloRequest) XXX_DiscardUnknown() {
    xxx_messageInfo_HelloRequest.DiscardUnknown(m)
}

var xxx_messageInfo_HelloRequest proto.InternalMessageInfo

func (m *HelloRequest) GetName() string {
    if m != nil {
        return m.Name
    }
    return ""
}

// The response message containing the greetings
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_17b8c58d586b62f2, []int{1}
}

func (m *HelloReply) XXX_Unmarshal(b []byte) error {
    return xxx_messageInfo_HelloReply.Unmarshal(m, b)
}
func (m *HelloReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
    return xxx_messageInfo_HelloReply.Marshal(b, m, deterministic)
}
func (m *HelloReply) XXX_Merge(src proto.Message) {
    xxx_messageInfo_HelloReply.Merge(m, src)
}
func (m *HelloReply) XXX_Size() int {
    return xxx_messageInfo_HelloReply.Size(m)
}
func (m *HelloReply) XXX_DiscardUnknown() {
    xxx_messageInfo_HelloReply.DiscardUnknown(m)
}

var xxx_messageInfo_HelloReply proto.InternalMessageInfo

func (m *HelloReply) GetMessage() string {
    if m != nil {
        return m.Message
    }
    return ""
}

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

func init() { proto.RegisterFile("helloworld.proto", fileDescriptor_17b8c58d586b62f2) }

var fileDescriptor_17b8c58d586b62f2 = []byte{
    // 175 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xc8, 0x48, 0xcd, 0xc9,
    0xc9, 0x2f, 0xcf, 0x2f, 0xca, 0x49, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x42, 0x88,
    0x28, 0x29, 0x71, 0xf1, 0x78, 0x80, 0x78, 0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x42,
    0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0xb6, 0x92,
    0x1a, 0x17, 0x17, 0x54, 0x4d, 0x41, 0x4e, 0xa5, 0x90, 0x04, 0x17, 0x7b, 0x6e, 0x6a, 0x71, 0x71,
    0x62, 0x3a, 0x4c, 0x11, 0x8c, 0x6b, 0xe4, 0xc9, 0xc5, 0xee, 0x5e, 0x94, 0x9a, 0x5a, 0x92, 0x5a,
    0x24, 0x64, 0xc7, 0xc5, 0x11, 0x9c, 0x58, 0x09, 0xd6, 0x25, 0x24, 0xa1, 0x87, 0xe4, 0x02, 0x64,
    0xcb, 0xa4, 0xc4, 0xb0, 0xc8, 0x14, 0xe4, 0x54, 0x2a, 0x31, 0x38, 0x19, 0x70, 0x49, 0x67, 0xe6,
    0xeb, 0xa5, 0x17, 0x15, 0x24, 0xeb, 0xa5, 0x56, 0x24, 0xe6, 0x16, 0xe4, 0xa4, 0x16, 0x23, 0xa9,
    0x75, 0xe2, 0x07, 0x2b, 0x0e, 0x07, 0xb1, 0x03, 0x40, 0x5e, 0x0a, 0x60, 0x4c, 0x62, 0x03, 0xfb,
    0xcd, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x0f, 0xb7, 0xcd, 0xf2, 0xef, 0x00, 0x00, 0x00,
}

// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn

// 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.SupportPackageIsVersion4

// 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.ClientConn
}

func NewGreeterClient(cc *grpc.ClientConn) 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, "/helloworld.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)
}

func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(HelloRequest)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(GreeterServer).SayHello(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/helloworld.Greeter/SayHello",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
    }
    return interceptor(ctx, in, info, handler)
}

var _Greeter_serviceDesc = grpc.ServiceDesc{
    ServiceName: "helloworld.Greeter",
    HandlerType: (*GreeterServer)(nil),
    Methods: []grpc.MethodDesc{
        {
            MethodName: "SayHello",
            Handler:    _Greeter_SayHello_Handler,
        },
    },
    Streams:  []grpc.StreamDesc{},
    Metadata: "helloworld.proto",
}

生成文件包含服務(wù)端接口GreeterServer描述,客戶端greeterClient接口及實現(xiàn),以及HelloRequest、HelloResponse結(jié)構(gòu)體。

4、服務(wù)端

在server子目錄下創(chuàng)建server.go文件:

package main

import (
   "context"
   "net"

   "google.golang.org/grpc"
   pb "helloworld/proto"
   "google.golang.org/grpc/reflection"
   "google.golang.org/grpc/grpclog"
)

const (
   // Address gRPC服務(wù)地址
   port = ":50051"
)

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

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
   return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

func main() {
   lis, err := net.Listen("tcp", port)
   if err != nil {
      grpclog.Fatalf("failed to listen: %v", err)
   }
   // 實例化gRPC Server
   s := grpc.NewServer()
   // 注冊服務(wù)
   pb.RegisterGreeterServer(s, &server{})
   // Register reflection service on gRPC server.
   reflection.Register(s)
   if err := s.Serve(lis); err != nil {
      grpclog.Fatalf("failed to serve: %v", err)
   }
}

服務(wù)端引入編譯后的proto包,實現(xiàn)約定的SayHello接口方法,接口描述可以查看helloworld.pb.go文件中的GreeterServer接口描述。實例化grpc Server并注冊GreeterService,開始提供服務(wù)。

5、客戶端

客戶端使用gRPC訪問服務(wù)端:

package main

import (
   "context"
   "os"
   "time"

   "google.golang.org/grpc"
   pb "helloworld/proto"
   "log"
)

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

func main() {
   // Set up a connection to the server.
   conn, err := grpc.Dial(address, grpc.WithInsecure())
   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.Message)
}
// output:
// 2018/12/17 19:57:47 Greeting: Hello world

客戶端初始化連接后直接調(diào)用聲明的方法,即可向服務(wù)端發(fā)起請求。

6、運行測試

在server目錄下啟動Server:
go run main.go
在client目錄下啟動客戶端:
go run main.go
客戶端接收到服務(wù)端的響應(yīng):
2018/12/17 20:03:44 Greeting: Hello world

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

新聞標(biāo)題:gRPC快速入門(四)——gRPC快速入門-創(chuàng)新互聯(lián)
分享地址:http://muchs.cn/article10/dshgdo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、網(wǎng)站維護、自適應(yīng)網(wǎng)站、網(wǎng)站收錄全網(wǎng)營銷推廣、微信小程序

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)