[RPC Foundation Series 3] gRPC simple example

This article focuses on a simple example of Java using gRPC.

preface

We can't just look at principles and ignore practice, nor can we just focus on practice and ignore principles. We should give consideration to both!

In the previous two articles [RPC basic series 1] talk about RPC and [RPC basic series 2] understand the basic principles and differences between gRPC and Thrift, we can basically understand three important concepts: RPC, gRPC and Thrift. In this article, we will look at the use posture of gPRC.

gRPC example

code: git@github.com:lml200701158/rpc-study.git

Project structure

Let's take a look at the project structure first:

Generate protobuf file

helloworld.proto

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

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

A SayHello() method is provided here. The input parameter is HelloRequest and the return value is HelloReply. You can see that the proto file only defines the format of the input parameter and return value and the interface to be called. As for the internal implementation of the interface, the file doesn't care at all.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>rpc-study</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>grpc-demo</artifactId>

    <dependencies>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <version>1.14.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>1.14.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.14.0</version>
        </dependency>
    </dependencies>

    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.5.0.Final</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.5.1</version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.14.0:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>

        </plugins>
    </build>
</project>

In fact, the purpose of the build is to install the protobuf plug-in. There are actually two plug-ins that we need to use, namely protobuf:compile and protobuf:compile javanano. When we directly execute, the left file will be generated. GreeterGrpc provides a call interface. The Hello header file function is mainly to serialize data and then process the input and return values.

Some students may ask, you generate the file into target, and I want to put it in main In SRC, you can copy these files or generate them through tools:

  • Download protocol Exe tool, download address: https://github.com/protocolbuffers/protobuf/releases

  • Download the protocol Gen grpc plug-in at: http://jcenter.bintray.com/io/grpc/protoc-gen-grpc-java/

Server and client

HelloWorldClient.java

public class HelloWorldClient {
    private final ManagedChannel channel;
    private final GreeterGrpc.GreeterBlockingStub blockingStub;
    private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName());

    public HelloWorldClient(String host,int port){
        channel = ManagedChannelBuilder.forAddress(host,port)
                .usePlaintext(true)
                .build();

        blockingStub = GreeterGrpc.newBlockingStub(channel);
    }


    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }

    public  void greet(String name){
        HelloRequest request = HelloRequest.newBuilder().setName(name).build();
        HelloReply response;
        try{
            response = blockingStub.sayHello(request);
        } catch (StatusRuntimeException e)
        {
            logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
            return;
        }
        logger.info("Message from gRPC-Server: "+response.getMessage());
    }

    public static void main(String[] args) throws InterruptedException {
        HelloWorldClient client = new HelloWorldClient("127.0.0.1",50051);
        try{
            String user = "world";
            if (args.length > 0){
                user = args[0];
            }
            client.greet(user);
        }finally {
            client.shutdown();
        }
    }
}

This is too simple. Connect to the service port and call the sayHello() method.

HelloWorldServer.java

public class HelloWorldServer {
    private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName());

    private int port = 50051;
    private Server server;

    private void start() throws IOException {
        server = ServerBuilder.forPort(port)
                .addService(new GreeterImpl())
                .build()
                .start();
        logger.info("Server started, listening on " + port);

        Runtime.getRuntime().addShutdownHook(new Thread() {

            @Override
            public void run() {

                System.err.println("*** shutting down gRPC server since JVM is shutting down");
                HelloWorldServer.this.stop();
                System.err.println("*** server shut down");
            }
        });
    }

    private void stop() {
        if (server != null) {
            server.shutdown();
        }
    }

    //block until you exit the program
    private void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        final HelloWorldServer server = new HelloWorldServer();
        server.start();
        server.blockUntilShutdown();
    }

    //Implementation} defines a class that implements a service interface
    private class GreeterImpl extends GreeterGrpc.GreeterImplBase {
        @Override
        public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
            HelloReply reply = HelloReply.newBuilder().setMessage(("Hello " + req.getName())).build();
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
            System.out.println("Message from gRPC-Client:" + req.getName());
            System.out.println("Message Response:" + reply.getMessage());
        }
    }
}

It mainly implements the sayHello() method, which simply processes the data. The input parameter is "W · world" and the return is "Hello World"

Start service

Start the Server first and return as follows:

Restart the Client and return as follows:

At the same time, the Server returns the following:

Postscript

This Demo looks very simple. I TM actually spent most of the day. At first, I didn't know that I needed to execute two different plug-ins to generate protobuf. I thought I just needed to click protobuf:compile. As a result, I found that protobuf:compile javanano also needed to click.

I also like to do it myself. I feel that generating protobuf through plug-ins is not perfect. I want to manually generate protobuf files through my downloaded plug-ins. As a result, the manual generation is not done, and the automatic generation method is not available. It took me a long time to find that it is a cache problem. Finally, I directly execute "Invalidate Caches / Restart" to do it.

The candidate said "no zuo no die", but this process still needs to be experienced.

Welcome to the many more articles, please pay attention to the official account of WeChat public, "the road of Lou Tsai", pay attention to it and not lose your way.

Keywords: rpc

Added by pendelton on Sat, 25 Dec 2021 23:19:39 +0200