Go語(yǔ)言與gRpc

1. gRpc 概述

gRpc是什么 ?

gRPC是Google開(kāi)源的可以在任何環(huán)境中運(yùn)行的現(xiàn)代開(kāi)源高性能RPC框架。它可以通過(guò)可插拔的支持來(lái)有效地連接數(shù)據(jù)中心內(nèi)和跨數(shù)據(jù)中心的服務(wù)觉痛,以實(shí)現(xiàn)負(fù)載平衡态秧,跟蹤昂验,健康檢查和身份驗(yàn)證缘滥。它也適用于分布式計(jì)算的最后一英里券躁,以將設(shè)備惩坑,移動(dòng)應(yīng)用程序和瀏覽器連接到后端服務(wù)。

主要使用場(chǎng)景

  1. 在微服務(wù)風(fēng)格架構(gòu)中有效連接多語(yǔ)種服務(wù)
  2. 將移動(dòng)設(shè)備也拜,瀏覽器客戶(hù)端連接到后端服務(wù)
  3. 生成高效的客戶(hù)端庫(kù)

gRpc官方地址

https://grpc.io/

gRpc源碼托管地址

https://github.com/grpc/grpc

gRpc支持我們常見(jiàn)的編程語(yǔ)言(C++ java Python Go Ruby C# Node.js PHP Dart Objective-C ) ,這些編程語(yǔ)言基本都有對(duì)gRpc的實(shí)現(xiàn)

詳情可以參看 https://grpc.io/docs/

2. gRpc執(zhí)行概述

在 gRPC 里客戶(hù)端應(yīng)用可以像調(diào)用本地對(duì)象一樣直接調(diào)用另一臺(tái)不同的機(jī)器上服務(wù)端應(yīng)用的方法以舒,使得您能夠更容易地創(chuàng)建分布式應(yīng)用和服務(wù)。與許多 RPC 系統(tǒng)類(lèi)似慢哈,gRPC 也是基于以下理念:定義一個(gè)服務(wù)蔓钟,指定其能夠被遠(yuǎn)程調(diào)用的方法(包含參數(shù)和返回類(lèi)型)。在服務(wù)端實(shí)現(xiàn)這個(gè)接口卵贱,并運(yùn)行一個(gè) gRPC 服務(wù)器來(lái)處理客戶(hù)端調(diào)用滥沫。在客戶(hù)端擁有一個(gè)存根能夠像服務(wù)端一樣的方法。

grpc.png

通過(guò)任意編程語(yǔ)言創(chuàng)建的gRpc服務(wù)端和客戶(hù)端可以運(yùn)行在多種環(huán)境中,創(chuàng)建的gRpc服務(wù)端,可以通過(guò)任意編程語(yǔ)言編寫(xiě)的客戶(hù)端調(diào)用

gRpc默認(rèn)使用protocol buffers 對(duì)數(shù)據(jù)進(jìn)行序列化

關(guān)于Protobuf的詳情,請(qǐng)參看 https://developers.google.com/protocol-buffers

3. gRpc-go 安裝

gRpc 有多種語(yǔ)言的實(shí)現(xiàn)

  • C++: follow the instructions under the src/cpp directory
  • C#: NuGet package Grpc
  • Dart: pub package grpc
  • Go: go get google.golang.org/grpc
  • Java: Use JARs from Maven Central Repository
  • Node: npm install grpc
  • Objective-C: Add gRPC-ProtoRPC dependency to podspec
  • PHP: pecl install grpc
  • Python: pip install grpcio
  • Ruby: gem install grpc
  • WebJS: follow the grpc-web instructions
Language Source
Shared C [core library] src/core
C++ src/cpp
Ruby src/ruby
Python src/python
PHP src/php
C# (core library based) src/csharp
Objective-C src/objective-c
Java grpc-java
Go grpc-go
NodeJS grpc-node
WebJS grpc-web
Dart grpc-dart
.NET (pure C# impl.) grpc-dotnet

grpc- go 是gRpc庫(kù)的Golang 實(shí)現(xiàn)版本,也是我們需要安裝的版本(根據(jù)自己的開(kāi)發(fā)語(yǔ)言選擇安裝)

安裝細(xì)節(jié)

進(jìn)入GOPATH目錄下執(zhí)行如下命令

go get -u google.golang.org/grpc

不出意外的話會(huì)安裝失敗,報(bào)錯(cuò)信息如下:

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)

這怎么辦呢?來(lái)來(lái)?yè)Q個(gè)姿勢(shì)繼續(xù)操作

下載 grpc-go 的源碼包和依賴(lài)包

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
git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto

下載完成之后 ,執(zhí)行安裝命令

cd $GOPATH/src
go install google.golang.org/grpc

因?yàn)間rpc默認(rèn)使用Protocol buffers

所以必須安裝 Protocol Buffers 編譯器,安裝步驟省略

$ protoc --version
libprotoc 3.11.0

我們開(kāi)發(fā)語(yǔ)言是Golang,所以也需要安裝protobuf文件的Go語(yǔ)言代碼生成插件

go get github.com/golang/protobuf/protoc-gen-go 

4. gRpc使用

上面的基礎(chǔ)環(huán)境具備之后,我們就可以快樂(lè)的使用gRpc開(kāi)發(fā)服務(wù)了

我們梳理一下gRpc框架使用的最基礎(chǔ)的流程:

  1. 編寫(xiě)Protobuf 文件,在Protobuf文件中定義服務(wù)和接口

  2. 自動(dòng)生成Go語(yǔ)言代碼.

    這里主要是指安裝的protoc-gen-go 插件然后指定參數(shù)生成兼容gRpc框架的Go語(yǔ)言代碼

  3. 服務(wù)接口的實(shí)現(xiàn)

  4. gRpc服務(wù)端實(shí)現(xiàn)

  5. gRpc客戶(hù)端實(shí)現(xiàn)

在gRpc安裝完成之后會(huì)有如下的一個(gè)目錄存在

$GOPATH/src/google.golang.org/grpc/examples

gRpc的很多功能的使用示例都在其中,我們學(xué)習(xí)gRpc可以多看看這個(gè)目錄中的文件

step1 : 編寫(xiě)一個(gè).proto 文件,文件名自己擬定

例如: demo5.proto

syntax = "proto3";
package example;
// 添加服務(wù)
service Demo5 {
    // 定義服務(wù)接口
    rpc GetInfo (Demo5Request) returns (Demo5Response) {
    }
    rpc SetName (Demo5Request) returns (Demo5Response) {
    }
}
message Demo5Request {
    string name = 1;
    int32 age = 2;
    enum Gender {
        MALE = 0;
        FEMALE = 1;
    }
    message Other {
        string addr = 1;
        string hobby = 2;
        Gender g = 3;
    }
    Other info = 3;
}
message Demo5Response {
    string info = 1;
}

step2 : 自動(dòng)生成Go語(yǔ)言代碼

執(zhí)行完下面的命令,將生成代碼文件 demo5.pb.go

 protoc --go_out=plugins=grpc:. example/demo5.proto

demo5.pb.go 具體內(nèi)容如下(在開(kāi)發(fā)中不太會(huì)去關(guān)注其中的內(nèi)容)

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

package example

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"
)

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

type Demo5Request_Gender int32

const (
    Demo5Request_MALE   Demo5Request_Gender = 0
    Demo5Request_FEMALE Demo5Request_Gender = 1
)

var Demo5Request_Gender_name = map[int32]string{
    0: "MALE",
    1: "FEMALE",
}

var Demo5Request_Gender_value = map[string]int32{
    "MALE":   0,
    "FEMALE": 1,
}

func (x Demo5Request_Gender) String() string {
    return proto.EnumName(Demo5Request_Gender_name, int32(x))
}

func (Demo5Request_Gender) EnumDescriptor() ([]byte, []int) {
    return fileDescriptor_dc43dfb84d83bd6d, []int{0, 0}
}

type Demo5Request struct {
    Name                 string              `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
    Age                  int32               `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
    Info                 *Demo5Request_Other `protobuf:"bytes,3,opt,name=info,proto3" json:"info,omitempty"`
    XXX_NoUnkeyedLiteral struct{}            `json:"-"`
    XXX_unrecognized     []byte              `json:"-"`
    XXX_sizecache        int32               `json:"-"`
}

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

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

var xxx_messageInfo_Demo5Request proto.InternalMessageInfo

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

func (m *Demo5Request) GetAge() int32 {
    if m != nil {
        return m.Age
    }
    return 0
}

func (m *Demo5Request) GetInfo() *Demo5Request_Other {
    if m != nil {
        return m.Info
    }
    return nil
}

type Demo5Request_Other struct {
    Addr                 string              `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"`
    Hobby                string              `protobuf:"bytes,2,opt,name=hobby,proto3" json:"hobby,omitempty"`
    G                    Demo5Request_Gender `protobuf:"varint,3,opt,name=g,proto3,enum=example.Demo5Request_Gender" json:"g,omitempty"`
    XXX_NoUnkeyedLiteral struct{}            `json:"-"`
    XXX_unrecognized     []byte              `json:"-"`
    XXX_sizecache        int32               `json:"-"`
}

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

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

var xxx_messageInfo_Demo5Request_Other proto.InternalMessageInfo

func (m *Demo5Request_Other) GetAddr() string {
    if m != nil {
        return m.Addr
    }
    return ""
}

func (m *Demo5Request_Other) GetHobby() string {
    if m != nil {
        return m.Hobby
    }
    return ""
}

func (m *Demo5Request_Other) GetG() Demo5Request_Gender {
    if m != nil {
        return m.G
    }
    return Demo5Request_MALE
}

type Demo5Response struct {
    Info                 string   `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}

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

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

var xxx_messageInfo_Demo5Response proto.InternalMessageInfo

func (m *Demo5Response) GetInfo() string {
    if m != nil {
        return m.Info
    }
    return ""
}

func init() {
    proto.RegisterEnum("example.Demo5Request_Gender", Demo5Request_Gender_name, Demo5Request_Gender_value)
    proto.RegisterType((*Demo5Request)(nil), "example.Demo5Request")
    proto.RegisterType((*Demo5Request_Other)(nil), "example.Demo5Request.Other")
    proto.RegisterType((*Demo5Response)(nil), "example.Demo5Response")
}

func init() { proto.RegisterFile("example/demo5.proto", fileDescriptor_dc43dfb84d83bd6d) }

var fileDescriptor_dc43dfb84d83bd6d = []byte{
    // 271 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4e, 0xad, 0x48, 0xcc,
    0x2d, 0xc8, 0x49, 0xd5, 0x4f, 0x49, 0xcd, 0xcd, 0x37, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17,
    0x62, 0x87, 0x0a, 0x2a, 0x3d, 0x61, 0xe4, 0xe2, 0x71, 0x01, 0x49, 0x04, 0xa5, 0x16, 0x96, 0xa6,
    0x16, 0x97, 0x08, 0x09, 0x71, 0xb1, 0xe4, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70,
    0x06, 0x81, 0xd9, 0x42, 0x02, 0x5c, 0xcc, 0x89, 0xe9, 0xa9, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xac,
    0x41, 0x20, 0xa6, 0x90, 0x3e, 0x17, 0x4b, 0x66, 0x5e, 0x5a, 0xbe, 0x04, 0xb3, 0x02, 0xa3, 0x06,
    0xb7, 0x91, 0xb4, 0x1e, 0xd4, 0x38, 0x3d, 0x64, 0xa3, 0xf4, 0xfc, 0x4b, 0x32, 0x52, 0x8b, 0x82,
    0xc0, 0x0a, 0xa5, 0x62, 0xb9, 0x58, 0xc1, 0x5c, 0x90, 0xf9, 0x89, 0x29, 0x29, 0x45, 0x30, 0xf3,
    0x41, 0x6c, 0x21, 0x11, 0x2e, 0xd6, 0x8c, 0xfc, 0xa4, 0xa4, 0x4a, 0xb0, 0x0d, 0x9c, 0x41, 0x10,
    0x8e, 0x90, 0x16, 0x17, 0x63, 0x3a, 0xd8, 0x02, 0x3e, 0x23, 0x19, 0xec, 0x16, 0xb8, 0xa7, 0xe6,
    0xa5, 0xa4, 0x16, 0x05, 0x31, 0xa6, 0x2b, 0xc9, 0x71, 0xb1, 0x41, 0x38, 0x42, 0x1c, 0x5c, 0x2c,
    0xbe, 0x8e, 0x3e, 0xae, 0x02, 0x0c, 0x42, 0x5c, 0x5c, 0x6c, 0x6e, 0xae, 0x60, 0x36, 0xa3, 0x92,
    0x32, 0x17, 0x2f, 0x54, 0x67, 0x71, 0x41, 0x7e, 0x5e, 0x71, 0x2a, 0xc8, 0x19, 0x60, 0x0f, 0x40,
    0x9d, 0x01, 0x62, 0x1b, 0xd5, 0x73, 0xb1, 0x82, 0x15, 0x09, 0x59, 0x71, 0xb1, 0xbb, 0xa7, 0x96,
    0x78, 0xe6, 0xa5, 0xe5, 0x0b, 0x89, 0x62, 0xb5, 0x59, 0x4a, 0x0c, 0x5d, 0x18, 0x62, 0xac, 0x12,
    0x03, 0x48, 0x6f, 0x70, 0x6a, 0x89, 0x1f, 0x28, 0xd8, 0x48, 0xd5, 0x9b, 0xc4, 0x06, 0x8e, 0x1c,
    0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x16, 0x42, 0x94, 0xe0, 0xb3, 0x01, 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

// Demo5Client is the client API for Demo5 service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type Demo5Client interface {
    GetInfo(ctx context.Context, in *Demo5Request, opts ...grpc.CallOption) (*Demo5Response, error)
    SetName(ctx context.Context, in *Demo5Request, opts ...grpc.CallOption) (*Demo5Response, error)
}

type demo5Client struct {
    cc *grpc.ClientConn
}

func NewDemo5Client(cc *grpc.ClientConn) Demo5Client {
    return &demo5Client{cc}
}

func (c *demo5Client) GetInfo(ctx context.Context, in *Demo5Request, opts ...grpc.CallOption) (*Demo5Response, error) {
    out := new(Demo5Response)
    err := c.cc.Invoke(ctx, "/example.Demo5/GetInfo", in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

func (c *demo5Client) SetName(ctx context.Context, in *Demo5Request, opts ...grpc.CallOption) (*Demo5Response, error) {
    out := new(Demo5Response)
    err := c.cc.Invoke(ctx, "/example.Demo5/SetName", in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

// Demo5Server is the server API for Demo5 service.
type Demo5Server interface {
    GetInfo(context.Context, *Demo5Request) (*Demo5Response, error)
    SetName(context.Context, *Demo5Request) (*Demo5Response, error)
}

// UnimplementedDemo5Server can be embedded to have forward compatible implementations.
type UnimplementedDemo5Server struct {
}

func (*UnimplementedDemo5Server) GetInfo(ctx context.Context, req *Demo5Request) (*Demo5Response, error) {
    return nil, status.Errorf(codes.Unimplemented, "method GetInfo not implemented")
}
func (*UnimplementedDemo5Server) SetName(ctx context.Context, req *Demo5Request) (*Demo5Response, error) {
    return nil, status.Errorf(codes.Unimplemented, "method SetName not implemented")
}

func RegisterDemo5Server(s *grpc.Server, srv Demo5Server) {
    s.RegisterService(&_Demo5_serviceDesc, srv)
}

func _Demo5_GetInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(Demo5Request)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(Demo5Server).GetInfo(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/example.Demo5/GetInfo",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(Demo5Server).GetInfo(ctx, req.(*Demo5Request))
    }
    return interceptor(ctx, in, info, handler)
}

func _Demo5_SetName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(Demo5Request)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(Demo5Server).SetName(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/example.Demo5/SetName",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(Demo5Server).SetName(ctx, req.(*Demo5Request))
    }
    return interceptor(ctx, in, info, handler)
}

var _Demo5_serviceDesc = grpc.ServiceDesc{
    ServiceName: "example.Demo5",
    HandlerType: (*Demo5Server)(nil),
    Methods: []grpc.MethodDesc{
        {
            MethodName: "GetInfo",
            Handler:    _Demo5_GetInfo_Handler,
        },
        {
            MethodName: "SetName",
            Handler:    _Demo5_SetName_Handler,
        },
    },
    Streams:  []grpc.StreamDesc{},
    Metadata: "example/demo5.proto",
}

step3 : gRpc服務(wù)端實(shí)現(xiàn)

具體服務(wù)的實(shí)現(xiàn)代碼可以單獨(dú)放在一個(gè)文件中,此處我們都放在了gRpc服務(wù)端代碼文件中

文件名: grpc_demo5_server.go

package main

import (
    pb "GoNote/chapter10/demo9/example"
    "fmt"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    "log"
    "net"
)

// 實(shí)現(xiàn)服務(wù)
type Demo5Server struct {
    pb.UnimplementedDemo5Server
}
// 實(shí)現(xiàn)服務(wù)定義的接口
func (d *Demo5Server) GetInfo(ctx context.Context, in *pb.Demo5Request) (*pb.Demo5Response, error) {
    InfoS := fmt.Sprintf("my name is %s, i am %d, i live in %s", in.Name, in.Age, in.Info.Addr)
    return &pb.Demo5Response{Info: InfoS}, nil
}
func (d *Demo5Server) SetName(ctx context.Context, in *pb.Demo5Request) (*pb.Demo5Response, error) {
    return &pb.Demo5Response{Info: "getName"}, nil
}
func main() {
    // 監(jiān)聽(tīng)8080端口
    listen, err := net.Listen("tcp", ":8080")
    if err != nil {
        log.Fatal("failed to listen : ", err.Error())
    }
    // 創(chuàng)建一個(gè)沒(méi)有注冊(cè)服務(wù)的新的gRpc服務(wù)器
    s := grpc.NewServer()
    // 注冊(cè)服務(wù)
    pb.RegisterDemo5Server(s, &Demo5Server{})
    fmt.Println("gRpc 服務(wù)端開(kāi)啟")
    // 接收gRpc請(qǐng)求
    if err := s.Serve(listen); err != nil {
        log.Fatal("this is error : ", err.Error())
    }
}

step4 : gRpc客戶(hù)端實(shí)現(xiàn)

文件名: grpc_demo5_client.go

package main

import (
    pb "GoNote/chapter10/demo9/example"
    "fmt"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    "log"
    "time"
)

func main() {
    // 創(chuàng)建一個(gè)客戶(hù)端連接
    conn, err := grpc.Dial(":8080", grpc.WithInsecure(), grpc.WithBlock())
    if err != nil {
        log.Fatal("connect failed : ", err.Error())
    }
    // 關(guān)閉客戶(hù)端連接
    defer conn.Close()
    // 客戶(hù)端服務(wù)api
    client := pb.NewDemo5Client(conn)
    ctx, cancel := context.WithTimeout(context.Background(), time.Second*1)
    defer cancel()
    // 客戶(hù)端請(qǐng)求數(shù)據(jù)
    req := pb.Demo5Request{
        Name: "Tom",
        Age:  99,
        Info: &pb.Demo5Request_Other{
            Addr:  "Beijing",
            Hobby: "climbing",
            G:     0,
        },
    }
    // 調(diào)用服務(wù)接口
    r, err := client.GetInfo(ctx, &req)
    if err != nil {
        log.Fatal("called failed : ", err.Error())
    }
    // 打印結(jié)果
    fmt.Println(r.Info)
}

測(cè)試

$ go run grpc_demo5_server.go
gRpc 服務(wù)端開(kāi)啟
$ go run grpc_demo5_client.go
my name is Tom, i am 99, i live in Beijing
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末键俱,一起剝皮案震驚了整個(gè)濱河市兰绣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌编振,老刑警劉巖缀辩,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡雌澄,警方通過(guò)查閱死者的電腦和手機(jī)斋泄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)镐牺,“玉大人炫掐,你說(shuō)我怎么就攤上這事〔墙В” “怎么了募胃?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)畦浓。 經(jīng)常有香客問(wèn)我痹束,道長(zhǎng),這世上最難降的妖魔是什么讶请? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任祷嘶,我火速辦了婚禮,結(jié)果婚禮上夺溢,老公的妹妹穿的比我還像新娘论巍。我一直安慰自己,他們只是感情好风响,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布嘉汰。 她就那樣靜靜地躺著,像睡著了一般状勤。 火紅的嫁衣襯著肌膚如雪鞋怀。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天持搜,我揣著相機(jī)與錄音密似,去河邊找鬼。 笑死朵诫,一個(gè)胖子當(dāng)著我的面吹牛辛友,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播剪返,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼邓梅!你這毒婦竟也來(lái)了脱盲?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤日缨,失蹤者是張志新(化名)和其女友劉穎钱反,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡面哥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年哎壳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尚卫。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡归榕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吱涉,到底是詐尸還是另有隱情刹泄,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布怎爵,位于F島的核電站特石,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鳖链。R本人自食惡果不足惜姆蘸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芙委。 院中可真熱鬧逞敷,春花似錦、人聲如沸题山。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)顶瞳。三九已至玖姑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間慨菱,已是汗流浹背焰络。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留符喝,地道東北人闪彼。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像协饲,于是被迫代替她去往敵國(guó)和親畏腕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • gRPC 是一個(gè)高性能茉稠、通用的開(kāi)源RPC框架描馅,基于HTTP/2協(xié)議標(biāo)準(zhǔn)和Protobuf序列化協(xié)議開(kāi)發(fā),支持眾多的...
    小波同學(xué)閱讀 19,494評(píng)論 6 19
  • 原文出處:gRPC gRPC分享 概述 gRPC 一開(kāi)始由 google 開(kāi)發(fā)而线,是一款語(yǔ)言中立铭污、平臺(tái)中立恋日、開(kāi)源的遠(yuǎn)...
    小波同學(xué)閱讀 7,222評(píng)論 0 18
  • 1.簡(jiǎn)介 在gRPC中,客戶(hù)端應(yīng)用程序可以直接調(diào)用不同計(jì)算機(jī)上的服務(wù)器應(yīng)用程序上的方法嘹狞,就像它是本地對(duì)象一樣岂膳,使您...
    第八共同體閱讀 1,880評(píng)論 0 6
  • 凡事有所保留,此法能確保你在他人心中的重要性磅网,任何時(shí)候你都不能一下用盡你所有的才能和力量谈截。 知道怎樣才能依靠自己。...
    哲與思閱讀 31評(píng)論 0 1
  • 昨晚我和先生第一次睡覺(jué)時(shí)關(guān)上臥室門(mén)知市,感覺(jué)真的挺不錯(cuò)傻盟。先生不再因孩子夜里有動(dòng)靜而驚醒,影響先生休息嫂丙;而孩子也因?yàn)槲覀?..
    修靜氣閱讀 134評(píng)論 0 2