preface

Hello everyone, I am fry fish, this chapter will use Go to write gRPC Server and Client, let them communicate with each other. The following libraries are used on top of this:

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

The installation

gRPC

go get -u google.golang.org/grpc
Copy the code

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 track of.zipcdProtobuf-3.5.1 /./configure make make installCopy the code

Check whether the installation is successful

protoc --version
Copy the code

If the following error occurs, execute ldConfig naming to resolve the problem

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

Protoc Plugin

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

If there is a problem with the installation environment, please refer to my previous article “Introduction and environment installation” in detail, no further details

gRPC

This section begins the formal preparation of gRPC related procedures, get on the bus together 😄

graphic

The directory structure

├─ ├─ proto ├─ search. Proto ├─ ├.goCopy the code

IDL

write

In the search.proto file in 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;
}
Copy the code

generate

Run the following command in the proto folder:

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

The proto file we defined refers to RPC services, and RPC code is not generated by default, so we need to give plugins to protoc-gen-go to say please support RPC (gRPC specified here).

  • –go_out=. : Sets the directory to output the Go code

This directive loads the protoc-gen-go plug-in to generate go code with.pb.go as the file suffix

  • : (colon)

The colon acts as a delimiter, followed by the desired set of arguments. If this does not involve RPC, the command can be simplified as follows:

$ protoc --go_out=. *.proto
Copy the code

Note: I suggest you look at the.pb.go files generated by the two commands. What are the differences

Generated after

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 {
	ifm ! = nil {return m.Request
	}
	return ""
}
Copy the code

By reading this section of code, you can see that it mainly involves the following aspects:

  • Convert field names from underscore to capital hump mode (field export)
  • Generates a set of Getters methods that make it easy to handle some cases of null pointer values
  • The ProtoMessage method implements the proto.Message interface
  • Generate Rest methods to restore the Protobuf structure to zero
  • Repeated is converted 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, }Copy the code

And this part of the code is basically around fileDescriptor, so fileDescriptor_search_8b45f79ee13ff6a3 is a compiled proto file, and each method has a Descriptor method, Represents the specific Message Field of this method in the fileDescriptor

Server

This section will write the basic gRPC Server template 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)
	iferr ! = nil { log.Fatalf("net.Listen err: %v", err)
	}

	server.Serve(lis)
}
Copy the code
  • Create a gRPC Server object that you can think of as an abstract object on the Server side
  • Register the SearchService, which contains the server-side interface that needs to be invoked, with the gRPC Server’s internal registry. In this way, when a request is received, the server interface can be discovered through internal service discovery and transferred for logical processing
  • Example Create Listen to Listen for 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:

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())
	iferr ! = 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",})iferr ! = nil { log.Fatalf("client.Search err: %v", err)
	}

	log.Printf("resp: %s", resp.GetResponse())
}
Copy the code
  • Create a connection interaction with a given target (server)
  • Create a client object for the SearchService
  • Sends an RPC request, waits for a synchronous response, and returns the response result after receiving a callback
  • Output response results

validation

Start the Server

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

Start the Client

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

conclusion

In this chapter, we have introduced Protobuf and gRPC Client/Server respectively. I hope you can write a Demo for in-depth understanding in combination with the content described in the article. It will certainly be better 🤔

?

If you have any questions or mistakes, welcome to raise questions or give correction opinions on issues. If you like or are helpful to you, welcome Star, which is a kind of encouragement and promotion for the author.

My official account

reference

Sample code for this series

  • go-grpc-example