banner
biuaxia

biuaxia

"万物皆有裂痕,那是光进来的地方。"
github
bilibili
tg_channel

【Reprint】Getting Started with gRPC

title: [Reprint] Getting Started with gRPC
date: 2021-08-09 16:36:33
comment: false
toc: true
category:

  • Golang
  • gRPC
    tags:
  • Reprint
  • Go
  • gRPC
  • Quick
  • Start

This article is a reprint from: Getting Started with gRPC | Li Wenzhou's Blog


RPC has become a popular concept in recent years, and with the rise of microservices architecture, the application of RPC is becoming more and more widespread. This article introduces the concepts of RPC and gRPC, and provides detailed code examples to demonstrate the basic usage of gRPC.

gRPC#

What is RPC#

In distributed computing, Remote Procedure Call (RPC) is a computer communication protocol. This protocol allows a program running on one computer to call a subroutine in another address space (typically on another computer on an open network) without the programmer having to explicitly code the details of the interaction. RPC is a client-server model, and the classic implementation is a system that interacts with information through "send request-receive response".

What is gRPC#

gRPC is a modern open-source high-performance RPC framework that can run in any environment. It was originally developed by Google and uses HTTP/2 as the transport protocol.

In gRPC, the client can directly call methods of server applications running on other machines as if they were calling local methods, making it easier to create distributed applications and services. Like many RPC systems, gRPC is based on defining a service and specifying methods that can be remotely called with parameters and return types. These methods are implemented in the server program and run gRPC services to handle client calls. On the client side, there is a stub that provides the same methods as the server.

image

Why use gRPC#

With gRPC, we can define services in a .proto file and implement clients and servers in any language that supports it. In turn, they can be applied in various scenarios, from Google's servers to your own tablets - gRPC helps you solve the complexity of communication between different languages and environments. Using protocol buffers also provides other benefits, including efficient serialization, simple IDL, and easy interface updates. In short, using gRPC makes it easier to write cross-language distributed code.

Installing gRPC#

Installing gRPC#

go get -u google.golang.org/grpc

Installing Protocol Buffers v3#

Install the protocol compiler used to generate gRPC service code. The simplest way to do this is to download the pre-compiled binary file (protoc-<version>-<platform>.zip) that matches your platform from the following link: https://github.com/google/protobuf/releases.

After downloading, follow these steps:

  1. Unzip the downloaded file.
  2. Add the path of the protoc binary file to the environment variable.

Next, execute the following command to install the Go plugin for protoc:

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

The protoc-gen-go plugin will be installed to $GOBIN, which is $GOPATH/bin by default. It must be in your $PATH so that the protocol compiler protoc can find it.

Installing Dependencies#

gRPC Development in Three Steps#

How many steps does it take to put an elephant in the refrigerator?

  1. Open the refrigerator door.
  2. Put the elephant in.
  3. Close the refrigerator door.

Similarly, gRPC development can be divided into three steps:

  1. Write the .proto file and generate language-specific source code.
  2. Write the server-side code.
  3. Write the client-side code.

gRPC Getting Started Example#

Writing Proto Code#

gRPC is based on Protocol Buffers.

Protocol Buffers is a language- and platform-neutral mechanism for serializing structured data. With Protocol Buffers, you define structured data once and then you can use special generated source code to easily write and read structured data to and from a variety of data streams using a variety of languages.

You can search online for tutorials on Protocol Buffers. This article assumes that readers are familiar with Protocol Buffers.

syntax = "proto3"; // Version declaration, using Protocol Buffers v3

package pb; // Package name

// Define a greeting service
service Greeter {
    // SayHello method
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// A request message containing a name
message HelloRequest {
    string name = 1;
}

// A response message containing a greeting
message HelloReply {
    string message = 1;
}

Execute the following command to generate Go language source code:

protoc -I helloworld/ helloworld/pb/helloworld.proto --go_out=plugins=grpc:helloworld

The helloworld.pb.go file will be generated in the gRPC_demo/helloworld/pb directory.

Writing Go Server Code#

package main

import (
	"fmt"
	"net"

	pb "gRPC_demo/helloworld/pb"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

type server struct{}

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

func main() {
	// Listen on port 8972
	lis, err := net.Listen("tcp", ":8972")
	if err != nil {
		fmt.Printf("failed to listen: %v", err)
		return
	}
	s := grpc.NewServer() // Create a gRPC server
	pb.RegisterGreeterServer(s, &server{}) // Register the service on the gRPC server

	reflection.Register(s) // Register server reflection service on the given gRPC server
	// Serve accepts incoming connections on lis, creates a ServerTransport and a server goroutine for each. 
	// The goroutine reads gRPC requests and then calls the registered handlers to reply to them.
	err = s.Serve(lis)
	if err != nil {
		fmt.Printf("failed to serve: %v", err)
		return
	}
}

Save the above code to the gRPC_demo/helloworld/server/server.go file, compile and execute it:

cd helloworld/server
go build
./server

Writing Go Client Code#

package main

import (
	"context"
	"fmt"

	pb "gRPC_demo/helloworld/pb"
	"google.golang.org/grpc"
)

func main() {
	// Connect to the server
	conn, err := grpc.Dial(":8972", grpc.WithInsecure())
	if err != nil {
		fmt.Printf("faild to connect: %v", err)
	}
	defer conn.Close()

	c := pb.NewGreeterClient(conn)
	// Call the SayHello method on the server
	r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: "q1mi"})
	if err != nil {
		fmt.Printf("could not greet: %v", err)
	}
	fmt.Printf("Greeting: %s !\n", r.Message)
}

Save the above code to the gRPC_demo/helloworld/client/client.go file, compile and execute it:

cd helloworld/client/
go build
./client

The output will be as follows (note that you need to start the server before starting the client):

$ ./client 
Greeting: Hello q1mi!

At this point, our directory structure looks like this:

./gRPC_demo
├── go.mod
├── go.sum
└── helloworld
    ├── client
   ├── client
   └── client.go
   ├── client.py
    ├── pb
   ├── helloworld.pb.go
   └── helloworld.proto
    └── server
        ├── server
        └── server.go

Cross-Language gRPC Invocation#

Next, let's demonstrate how to use gRPC to achieve cross-language RPC calls.

We will use Python to write the client and send RPC requests to the server written in Go.

Generating Python Code#

Execute the following command in the gRPC_demo directory:

python -m grpc_tools.protoc -I helloworld/pb/ --python_out=helloworld/client/ --grpc_python_out=helloworld/client/ helloworld/pb/helloworld.proto

This command will generate two Python files in the gRPC_demo/helloworld/client/ directory:

helloworld_pb2.py
helloworld_pb2_grpc.py

Writing Python Client#

Create a client.py file in the gRPC_demo/helloworld/client/ directory with the following content:

# coding=utf-8

import logging

import grpc

import helloworld_pb2
import helloworld_pb2_grpc

def run():
    # Note (gRPC Python Team): .close() is available on the channel and should be used in circumstances in which
    # a with statement is not applicable.
    with grpc.insecure_channel('localhost:8972') as channel:
        stub = helloworld_pb2_grpc.GreeterStub(channel)
        response = stub.SayHello(helloworld_pb2.HelloRequest(name='q1mi'))
    print("Greeter client received: {}!".format(response.message))

if __name__ == '__main__':
    logging.basicConfig()
    run()

Save and execute the above code, and the output will be as follows:

gRPC_demo $ python helloworld/client/client.py 
Greeter client received: Hello q1mi!

Now we have successfully used a Python client to call the server written in Go.

Click the link on the right to view the complete code: Complete gRPC_demo Code

There are more advanced usages of gRPC, to be continued...

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.