Bring in grpc: grpcclient and server

  golang, grpc, javascript, php, protobuf

Bring in grpc: grpcclient and server

Original address:Bring in grpc: grpcclient and server

Project address:go-grpc-example

Preface

This chapter will use Go to write gRPC Server and Client to communicate with each other. The following libraries will be used on top of this:

  • google.golang.org/grpc
  • github.com/golang/protobuf/protoc-gen-go

Installation

gRPC

go get -u google.golang.org/grpc

Protocol Buffers v3

wget https://github.com/google/protobuf/releases/download/v3.5.1/protobuf-all-3.5.1.zip
unzip protobuf-all-3.5.1.zip
cd protobuf-3.5.1/
./configure
make
make install

Check whether the installation was successful

protoc --version

If the following error occurs, executeldconfigNaming can solve this problem.

protoc: error while loading shared libraries: libprotobuf.so.15: cannot open shared object file: No such file or directory

Protoc Plugin

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

If there are problems with the installation environment, please refer to my previous articles.Introduction and Environmental InstallationIt is described in detail and will not be repeated here.

gRPC

This section begins to formally write gRPC-related programs. Let’s get on the bus together.

Icon

image

directory structure

$ tree go-grpc-example 
go-grpc-example
├── client
├── proto
│   └── search.proto
└── server.go

IDL

write

In the Search. proto file under the Proto folder, write the following:

syntax = "proto3";

package proto;

service SearchService {
    rpc Search(SearchRequest) returns (SearchResponse) {}
}

message SearchRequest {
    string request = 1;
}

message SearchResponse {
    string response = 1;
}

generate

Execute the following command under the proto folder:

$ protoc --go_out=plugins=grpc:. *.proto
  • Plugins=plugin1+plugin2: Specifies the list of child plug-ins to load

The proto file we defined involves RPC services, but RPC code will not be generated by default, so it needs to be givenpluginsParameter passed toprotoc-gen-go, tell it, please support RPC (gRPC is specified here)

  • -Go _ out =.: sets the directory for go code output

This instruction will load protoc-gen-Go plug-in to generate go code, and the generated file will have. pb.go as the file suffix.

  • : (colon)

The colon acts as a delimiter, followed by the desired parameter set. If RPC is not involved in this place, the command can be simplified as:

$ protoc --go_out=. *.proto

Note: It is suggested that you look at the. pb.go files generated by the two commands. What are the differences between them?

After generation

After executing the command, you will get a. pb.go file with the following contents:

type SearchRequest struct {
    Request              string   `protobuf:"bytes,1,opt,name=request" json:"request,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}

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

func (m *SearchRequest) GetRequest() string {
    if m != nil {
        return m.Request
    }
    return ""
}

By reading this part of the code, we can know that it mainly involves the following aspects:

  • The field name is converted from small underline to uppercase hump mode (field export)
  • Generating a set of Getters methods can facilitate handling some null pointer values
  • The ProtoMessage method implements the proto.Message interface.
  • The Rest method is generated to facilitate the restoration of the Protobuf structure to a zero value.
  • Repeated to slice
type SearchRequest struct {
    Request              string   `protobuf:"bytes,1,opt,name=request" json:"request,omitempty"`
}

func (*SearchRequest) Descriptor() ([]byte, []int) {
    return fileDescriptor_search_8b45f79ee13ff6a3, []int{0}
}

type SearchResponse struct {
    Response             string   `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"`
}

func (*SearchResponse) Descriptor() ([]byte, []int) {
    return fileDescriptor_search_8b45f79ee13ff6a3, []int{1}
}

...

func init() { proto.RegisterFile("search.proto", fileDescriptor_search_8b45f79ee13ff6a3) }

var fileDescriptor_search_8b45f79ee13ff6a3 = []byte{
    // 131 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0x4e, 0x4d, 0x2c,
    0x4a, 0xce, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x4a, 0x9a, 0x5c, 0xbc,
    0xc1, 0x60, 0xe1, 0xa0, 0xd4, 0xc2, 0xd2, 0xd4, 0xe2, 0x12, 0x21, 0x09, 0x2e, 0xf6, 0x22, 0x08,
    0x53, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08, 0xc6, 0x55, 0xd2, 0xe1, 0xe2, 0x83, 0x29, 0x2d,
    0x2e, 0xc8, 0xcf, 0x2b, 0x4e, 0x15, 0x92, 0xe2, 0xe2, 0x28, 0x82, 0xb2, 0xa1, 0x8a, 0xe1, 0x7c,
    0x23, 0x0f, 0x98, 0xc1, 0xc1, 0xa9, 0x45, 0x65, 0x99, 0xc9, 0xa9, 0x42, 0xe6, 0x5c, 0x6c, 0x10,
    0x01, 0x21, 0x11, 0x88, 0x13, 0xf4, 0x50, 0x2c, 0x96, 0x12, 0x45, 0x13, 0x85, 0x98, 0xa3, 0xc4,
    0x90, 0xc4, 0x06, 0x16, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xf3, 0xba, 0x74, 0x95, 0xc0,
    0x00, 0x00, 0x00,
}

And this part of the code is mainly aroundfileDescriptorGo ahead, herefileDescriptor_search_8b45f79ee13ff6a3Represents a compiled proto file, and each method contains a Descriptor method, which represents a method thatfileDescriptorMessage Field specified in

Server

This section will write the basic template of gRPC Server to complete a method call. Write the following to server.go:

package main

import (
    "context"
    "log"
    "net"

    "google.golang.org/grpc"

    pb "github.com/EDDYCJY/go-grpc-example/proto"
)

type SearchService struct{}

func (s *SearchService) Search(ctx context.Context, r *pb.SearchRequest) (*pb.SearchResponse, error) {
    return &pb.SearchResponse{Response: r.GetRequest() + " Server"}, nil
}

const PORT = "9001"

func main() {
    server := grpc.NewServer()
    pb.RegisterSearchServiceServer(server, &SearchService{})

    lis, err := net.Listen("tcp", ":"+PORT)
    if err != nil {
        log.Fatalf("net.Listen err: %v", err)
    }

    server.Serve(lis)
}
  • To create a gRPC Server object, you can understand it as an abstract object on the server side.
  • Register the SearchService (which contains the server interface to be called) to the internal registration center of gRPC Server. In this way, when receiving the request, the server interface can be found and transferred for logical processing through internal service discovery.
  • Create Listen, listen to TCP ports
  • GRPC Server starts lis.Accept until Stop or GracefulStop.

Client

Next, write the basic template of gRPC Go Client, open the client/client.go file and write the following contents:

package main

import (
    "context"
    "log"

    "google.golang.org/grpc"

    pb "github.com/EDDYCJY/go-grpc-example/proto"
)

const PORT = "9001"

func main() {
    conn, err := grpc.Dial(":"+PORT, grpc.WithInsecure())
    if err != nil {
        log.Fatalf("grpc.Dial err: %v", err)
    }
    defer conn.Close()

    client := pb.NewSearchServiceClient(conn)
    resp, err := client.Search(context.Background(), &pb.SearchRequest{
        Request: "gRPC",
    })
    if err != nil {
        log.Fatalf("client.Search err: %v", err)
    }

    log.Printf("resp: %s", resp.GetResponse())
}
  • Creates a connection interaction with a given target (server)
  • Create a client object for SearchService
  • Sending RPC request, waiting for synchronous response, and returning response result after callback
  • Output response results

Verification

Start Server

$ pwd
$GOPATH/github.com/EDDYCJY/go-grpc-example
$ go run server.go

Start Client

$ pwd             
$GOPATH/github.com/EDDYCJY/go-grpc-example/client
$ go run client.go 
2018/09/23 11:06:23 resp: gRPC Server

Summary

In this chapter, Protobuf and gRPC Client/Server are introduced respectively. I hope you can write another Demo in combination with the content in the article to have a deeper understanding. It will certainly be better.

Series catalog