Grpc Java implements various service types

Posted by nalleyp23 on Thu, 09 Dec 2021 08:27:29 +0100

gRPC implementation

With gRPC, we can define services once in a. proto file and generate clients and servers in any language supported by gRPC, which can run in a variety of environments from servers to computers in large data centers – gRPC handles different languages and environments for you. It also obtains all the advantages of using protocol buffers, including effective serialization, simple IDL and easy interface update.

There are four service types in grpc:

Simple rpc: This is a general rpc call. A request object corresponds to a return object

Server streaming rpc: a request object. The server can return multiple result objects

Client streaming rpc: the client passes in multiple request objects, and the server returns a response result

Bidirectional streaming rpc: combining client streaming rpc and server streaming rpc, multiple objects can be passed in and multiple response objects can be returned

grpc returns / accepts multiple instances in a streaming manner, which can be used for input and output parameters similar to indefinite length arrays

preparation

Create maven project grpc and generate proto interface project grpc PROTOS

Grpc PROTOS project

Create the interface file route under grpc PROTOS_ Guide.proto, as follows

// Using proto3 syntax
syntax = "proto3";

// Generate multiple classes
option java_multiple_files = true;

// Generate the package where the java class is located
option java_package = "io.grpc.examples.routeguide";

// Generate outer class class name
option java_outer_classname = "RouteGuideProto";

// Prefix of Objective-C class
option objc_class_prefix = "RTG";

// proto package name
package routeguide;

// Define RPC service RouteGuide
service RouteGuide {

    // Simple RPC accepts the simplerrpcreq parameter and returns an object of type simplerrpcres
    rpc GetFeature(SimpleRpcReq) returns (SimpleRpcRes) {}

    // Server to client streaming RPC, accept ServerToClientStreamRpcReq object parameters and return batch ServerToClientStreamRpcRes data
    rpc ListFeatures(ServerToClientStreamRpcReq) returns (stream ServerToClientStreamRpcRes) {}

    // Client to server streaming RPC, accept batch Point data, and return RouteSummary type objects
    rpc RecordRoute(stream ClientToServerStreamRpcReq) returns (ClientToServerStreamRpcReq) {}

    // Bidirectional streaming RPC, which accepts batch RouteNote type data and returns batch RouteNote type data
    rpc RouteChat(stream TwoWayStreamRpcReq) returns (stream TwoWayStreamRpcRes) {}
}

/** Simple RPC**/
// Point
message SimpleRpcReq {
    int32 latitude = 1;
    int32 longitude = 2;
}

// Feature
message SimpleRpcRes {
    string name = 1;
    Point location = 2;
}
/** Simple RPC**/


/** Server to client streaming RPC**/
message ServerToClientStreamRpcReq {
    Point lo = 1;
    Point hi = 2;
}

// Feature
message ServerToClientStreamRpcRes {
    string name = 1;
    Point location = 2;
}
/** Server to client streaming RPC**/


/** Client to server streaming RPC**/
// Point
message ClientToServerStreamRpcReq {
    Point lo = 1;
    Point hi = 2;
}

message ClientToServerStreamRpcRes {
    int32 point_count = 1;
    int32 feature_count = 2;
    int32 distance = 3;
    int32 elapsed_time = 4;
}
/** Client to server streaming RPC**/


/** Client to server streaming RPC**/
message TwoWayStreamRpcReq {
    Point location = 1;
    string message = 2;
}


message TwoWayStreamRpcRes {
    Point location = 1;
    string message = 2;
}
/** Client to server streaming RPC**/


message Point {
    int32 latitude = 1;
    int32 longitude = 2;
}

message Feature {
    string name = 1;
    Point location = 2;
}

grpc project

pom file contents are as follows

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.starnet</groupId>
    <artifactId>grpc</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>11</java.version>
        <grpc.version>1.29.0</grpc.version>
        <protobuf.version>3.11.0</protobuf.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <version>${grpc.version}</version>
        </dependency>

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>${grpc.version}</version>
        </dependency>

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>${grpc.version}</version>
        </dependency>

        <dependency> <!-- necessary for Java 9+ -->
            <groupId>org.apache.tomcat</groupId>
            <artifactId>annotations-api</artifactId>
            <version>6.0.53</version>
            <scope>provided</scope>
        </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:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
                    <protoSourceRoot>../grpc-protos</protoSourceRoot>
                </configuration>

                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>


</project>

Note that the protoSourceRoot configured in the protobuf plug-in is the absolute path or relative path of the protos interface directory, because the plug-in needs to find the proto file according to the directory to generate relevant code; If protoSourceRoot is not set, it defaults to the src/main/proto directory of the project

Generate grpc protobuf related classes

Execute in grpc directory or generate directly through Idea

mvn protobuf:compile
mvn protobuf:compile-custom

The corresponding code is generated in the target directory

code implementation

Server

Start gRPC Server

import io.grpc.Server;
import io.grpc.ServerBuilder;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class GRpcServer {

    private Server server;

    private void start() throws IOException {

        /* The port on which the server should run */
        int port = 50051;

        server = ServerBuilder.forPort(port)
                .addService(new RouteGuideService())  //Multiple modules can be added here
                .build()
                .start();

        System.out.println("Server started, listening on " + port);

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                // Use stderr here since the logger may have been reset by its JVM shutdown hook.
                System.err.println("shutting down gRPC server since JVM is shutting down");

                try {
                    GRpcServer.this.stop();
                } catch (InterruptedException e) {
                    e.printStackTrace(System.err);
                }

                System.err.println("server shut down");
            }
        });
    }

    private void stop() throws InterruptedException {

        if (server != null) {
            server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
        }
    }

    private void blockUntilShutdown() throws InterruptedException {

        if (server != null) {
            server.awaitTermination();
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {

        GRpcServer server = new GRpcServer();
        server.start();
        server.blockUntilShutdown();
    }
}

gRPC server processing

import io.grpc.examples.routeguide.*;
import io.grpc.stub.StreamObserver;

import java.util.ArrayList;
import java.util.List;

public class RouteGuideService extends RouteGuideGrpc.RouteGuideImplBase {

    /**
     * Simple RPC accepts the simplerrpcreq parameter and returns an object of type simplerrpcres
     * @param request
     * @param responseObserver
     */
    @Override
    public void getSimpleRpcRes(SimpleRpcReq request, StreamObserver<SimpleRpcRes> responseObserver) {

        Point location = Point.newBuilder()
                .setLatitude(request.getLatitude())
                .setLongitude(request.getLongitude())
                .build();;

        SimpleRpcRes simpleRpcRes = SimpleRpcRes
                .newBuilder()
                .setName("fuzhou")
                .setLocation(location)
                .build();

        // Send a message to the client through responseObserver.onNext
        responseObserver.onNext(simpleRpcRes);
        // Mark the completion of server response
        responseObserver.onCompleted();
    }

    /**
     * Server to client streaming RPC, accept ServerToClientStreamRpcReq object parameters and return batch ServerToClientStreamRpcRes data
     * @param request
     * @param responseObserver
     */
    @Override
    public void listServerToClientStreamRpcRes(ServerToClientStreamRpcReq request, StreamObserver<ServerToClientStreamRpcRes> responseObserver) {

        List<Point> pointList = new ArrayList<>();
        pointList.add(request.getLo());
        pointList.add(request.getHi());

        int i = 1;
        for (Point point : pointList) {
            ServerToClientStreamRpcRes res = ServerToClientStreamRpcRes.newBuilder()
                    .setName("fuzhou" + i++)
                    .setLocation(point)
                    .build();

            // Call responseObserver.onNext in a loop to send data to the client callback
            responseObserver.onNext(res);
        }

        responseObserver.onCompleted();
    }

    /**
     * Client to server streaming RPC, accept batch Point data, and return RouteSummary type objects
     * @param responseObserver
     * @return
     */
    @Override
    public StreamObserver<ClientToServerStreamRpcReq> getClientToServerStreamRpcRes(StreamObserver<ClientToServerStreamRpcRes> responseObserver) {

        // Construct observer client interaction
        return new StreamObserver<ClientToServerStreamRpcReq>() {
            int pointCount;

            // Response client
            @Override
            public void onNext(ClientToServerStreamRpcReq point) {

                System.out.println("point is " + point);
                pointCount++;
            }

            @Override
            public void onError(Throwable t) {

                System.out.println("client to server stream rpc is cancelled");
            }

            // Triggered when the client calls requestObserver.onCompleted(), marking that the server processing is completed
            @Override
            public void onCompleted() {

                // Callback client responseObserver.onNext
                responseObserver.onNext(ClientToServerStreamRpcRes.newBuilder().setPointCount(pointCount).build());

                // Callback client responseObserver.onCompleted flag completed
                responseObserver.onCompleted();
            }
        };
    }

    /**
     * Bidirectional streaming RPC, which accepts batch RouteNote type data and returns batch RouteNote type data
     * @param responseObserver
     * @return
     */
    @Override
    public StreamObserver<TwoWayStreamRpcReq> listTwoWayStreamRpcRes(StreamObserver<TwoWayStreamRpcRes> responseObserver) {

        // Construct observer client interaction
        return new StreamObserver<TwoWayStreamRpcReq>() {

            // Response client
            @Override
            public void onNext(TwoWayStreamRpcReq point) {

                // Callback client responseObserver.onNext
                responseObserver.onNext(TwoWayStreamRpcRes.newBuilder().setMessage("res" + point.getMessage())
                        .setLocation(Point.newBuilder()
                                .setLatitude(point.getLocation().getLatitude() + 100)
                                .setLongitude(point.getLocation().getLongitude() + 100)
                                .build())
                        .build());
            }

            @Override
            public void onError(Throwable t) {

                System.out.println("client to server stream rpc is cancelled");
            }

            // Triggered when the client calls requestObserver.onCompleted(), marking that the server processing is completed
            @Override
            public void onCompleted() {

                // Callback client responseObserver.onCompleted flag completed
                responseObserver.onCompleted();
            }
        };
    }
}

client

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.examples.routeguide.*;
import io.grpc.stub.StreamObserver;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class GRpcClient {

    //Remote connection manager, managing the lifecycle of connections
    private final ManagedChannel channel;
    private final RouteGuideGrpc.RouteGuideBlockingStub blockingStub;
    private final RouteGuideGrpc.RouteGuideStub stub;

    Random random = new Random();

    public GRpcClient(String host, int port) {
        //Initialize connection
        channel = ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext()
                .build();

        //Initialize remote service Stub
        blockingStub = RouteGuideGrpc.newBlockingStub(channel);
        stub = RouteGuideGrpc.newStub(channel);
    }


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

    public static void main(String[] args) throws Exception {

        GRpcClient client = new GRpcClient("127.0.0.1", 50051);

        // Simple gRPC interaction
        System.out.println("simple rpc start!!!!!!");
        SimpleRpcRes simpleRpcRes = client.getSimpleRpcRes(12, 16);
        System.out.println("simple rpc response: ");
        System.out.println(simpleRpcRes);
        System.out.println("simple rpc over!!!!!!");
        System.out.println("\n===================================================\n");


        // Server to client streaming interaction
        System.out.println("server to client stream rpc start!!!!!!");
        Iterator<ServerToClientStreamRpcRes> serverToClientStreamRpcResIterator = client.listServerToClientStreamRpcRes(11, 22, 666, 777);
        System.out.println("server to client stream rpc response: ");
        while (serverToClientStreamRpcResIterator.hasNext()) {
            System.out.println(serverToClientStreamRpcResIterator.next());
        }
        System.out.println("server to client stream rpc over!!!!!!");
        System.out.println("\n===================================================\n");


        // Client to server streaming interaction
        System.out.println("client to server stream rpc start!!!!!!");
        client.getClientToServerStreamRpcRes(10);
        System.out.println("client to server stream rpc over!!!!!!");
        System.out.println("\n===================================================\n");


        // Client to server streaming interaction
        System.out.println("two way stream rpc start!!!!!!");
        client.listTwoWayStreamRpcRes(5);
        System.out.println("two way stream rpc over!!!!!!");

        //Close connection
        client.shutdown();
    }

    public SimpleRpcRes getSimpleRpcRes(int lat, int lon) {

        // Construct service call parameter object
        SimpleRpcReq request = SimpleRpcReq.newBuilder().setLatitude(lat).setLongitude(lon).build();
        // Call remote service method
        return blockingStub.getSimpleRpcRes(request);
    }


    public Iterator<ServerToClientStreamRpcRes> listServerToClientStreamRpcRes(int lowLag, int lowLon, int highLag, int highLong) {

        // Construct service call parameter object
        ServerToClientStreamRpcReq request = ServerToClientStreamRpcReq.newBuilder()
                .setLo(Point.newBuilder().setLatitude(lowLag).setLongitude(lowLon).build())
                .setHi(Point.newBuilder().setLatitude(highLag).setLongitude(highLong).build()).build();
        // Call remote service method
        return blockingStub.listServerToClientStreamRpcRes(request);
    }

    private void getClientToServerStreamRpcRes(int pointNum) throws Exception {

        List<ClientToServerStreamRpcReq> pointList = new ArrayList<>();
        for (int i = 1; i <= pointNum; i++) {
            pointList.add(ClientToServerStreamRpcReq.newBuilder().setLatitude(i).setLongitude(i).build());
        }

        CountDownLatch finishLatch = new CountDownLatch(1);
        // Create responseObserver to call back the client from the server
        StreamObserver<ClientToServerStreamRpcRes> responseObserver = new StreamObserver<ClientToServerStreamRpcRes>() {

            // Response server responseObserver.onNext callback
            @Override
            public void onNext(ClientToServerStreamRpcRes res) {

                System.out.println("client to server stream rpc response: ");
                System.out.println(res);
            }

            // Response server responseObserver.onError callback
            @Override
            public void onError(Throwable t) {

                System.out.println("client to server stream is error " + t.getMessage() + ": " + t);
            }

            // Callback of responseObserver.onCompleted on the response server
            @Override
            public void onCompleted() {

                System.out.println("client to server stream, server has been over");
                finishLatch.countDown();
            }
        };

        // The call is initiated through asynchronous stub, and the parameter is responseObserver
        StreamObserver<ClientToServerStreamRpcReq> requestObserver = stub.getClientToServerStreamRpcRes(responseObserver);
        try {
            for (ClientToServerStreamRpcReq point : pointList) {
//                Thread.sleep(random.nextInt(1000) + 500);
                if (finishLatch.getCount() == 0) {
                    return;
                }
                // Call requestObserver.onNext several times to write data to the server
                requestObserver.onNext(point);
            }
        } catch (Exception e) {
            requestObserver.onError(e);
        }
        // Mark end of client write
        requestObserver.onCompleted();

        // Because the result is obtained asynchronously, sleep for one second, otherwise the program will be over
        Thread.sleep(1000);
    }

    private void listTwoWayStreamRpcRes(int pointNum) throws Exception {

        List<TwoWayStreamRpcReq> rpcReqList = new ArrayList<>();
        for (int i = 1; i <= pointNum; i++) {
            rpcReqList.add(TwoWayStreamRpcReq.newBuilder().setMessage("" + i)
                    .setLocation(Point.newBuilder().setLatitude(i).setLongitude(i).build())
                    .build());
        }

        CountDownLatch finishLatch = new CountDownLatch(1);
        // Create responseObserver to call back the client from the server
        StreamObserver<TwoWayStreamRpcRes> responseObserver = new StreamObserver<TwoWayStreamRpcRes>() {

            // Response server responseObserver.onNext callback
            @Override
            public void onNext(TwoWayStreamRpcRes res) {

                System.out.println("two way stream rpc response: ");
                System.out.println(res);
            }

            // Response server responseObserver.onError callback
            @Override
            public void onError(Throwable t) {

                System.out.println("two way stream is error " + t.getMessage() + ": " + t);
            }

            // Callback of responseObserver.onCompleted on the response server
            @Override
            public void onCompleted() {

                System.out.println("two way stream, server has been over");
                finishLatch.countDown();
            }
        };

        // The call is initiated through asynchronous stub, and the parameter is responseObserver
        StreamObserver<TwoWayStreamRpcReq> requestObserver = stub.listTwoWayStreamRpcRes(responseObserver);
        try {
            for (TwoWayStreamRpcReq point : rpcReqList) {
//                Thread.sleep(random.nextInt(1000) + 500);
                if (finishLatch.getCount() == 0) {
                    return;
                }
                // Call requestObserver.onNext several times to write data to the server
                requestObserver.onNext(point);
            }
        } catch (Exception e) {
            requestObserver.onError(e);
        }
        // Mark end of client write
        requestObserver.onCompleted();

        // Because the result is obtained asynchronously, sleep for one second, otherwise the program will be over
        Thread.sleep(1000);
    }
}

Topics: Java rpc