gRPC Java、Go、PHP使用例子

文章目录

    • 1、Protocol Buffers定义接口
      • 1.1、编写接口服务
      • 1.2、Protobuf基础数据类型
    • 2、服务器端实现
      • 2.1、生成gRPC服务类
      • 2.2、Java服务器端实现
    • 3、java、go、php客户端实现
      • 3.1、Java客户端实现
      • 3.2、Go客户端实现
      • 3.3、PHP客户端实现

本文例子是在Window平台测试,Java编写的gRPC服务器端,同时使用Java、Go、PHP编写客户端调用。

1、Protocol Buffers定义接口

1.1、编写接口服务

// 定义protocol buffers版本(proto3)
syntax = "proto3";

// 定义包名,避免协议消息类型之间的命名冲突。
package helloworld;

// 定义java格式
option java_multiple_files = true;
option java_package = "com.penngo.grpc";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

// 服务接口定义
service Greeter { 
  // 方法1定义
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  // 方法2定义
  rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}

// HelloRequest消息类型格式定义,
message HelloRequest {
  // name为定义字段名,1为消息传输中的字段编号,使用后,不应该改编号。
  string name = 1;
}

// HelloReply消息类型格式定义,
message HelloReply {
  // message为定义字段名,1为消息传输中的字段编号,使用后,不应该改编号。
  string message = 1;
}

1.2、Protobuf基础数据类型

    C++
    Java/Kotlin
    Python
    Go
    Ruby
    C#
    PHP
    Dart


    double
    
    double
    double
    float
    float64
    Float
    double
    float
    double


    float
   
    float
    float
    float
    float32
    Float
    float
    float
    double


    int32
  
    int32
    int
    int
    int32
    Fixnum or Bignum (as required)
    int
    integer
    int


    int64

    int64
    long
    int/long[4]
    int64
    Bignum
    long
    integer/string[6]
    Int64


    uint32
   
    uint32
    int[2]
    int/long[4]
    uint32
    Fixnum or Bignum (as required)
    uint
    integer
    int


    uint64
 
    uint64
    long[2]
    int/long[4]
    uint64
    Bignum
    ulong
    integer/string[6]
    Int64


    sint32
   
    int32
    int
    int
    int32
    Fixnum or Bignum (as required)
    int
    integer
    int


    sint64
    
    int64
    long
    int/long[4]
    int64
    Bignum
    long
    integer/string[6]
    Int64


    fixed32
  
    uint32
    int[2]
    int/long[4]
    uint32
    Fixnum or Bignum (as required)
    uint
    integer
    int


    fixed64
  
    uint64
    long[2]
    int/long[4]
    uint64
    Bignum
    ulong
    integer/string[6]
    Int64


    sfixed32
   
    int32
    int
    int
    int32
    Fixnum or Bignum (as required)
    int
    integer
    int


    sfixed64
   
    int64
    long
    int/long[4]
    int64
    Bignum
    long
    integer/string[6]
    Int64


    bool
   
    bool
    boolean
    bool
    bool
    TrueClass/FalseClass
    bool
    boolean
    bool


    string
    
    string
    String
    str/unicode[5]
    string
    String (UTF-8)
    string
    string
    String


    bytes
    
    string
    ByteString
    str (Python 2)
bytes (Python 3) []byte String (ASCII-8BIT) ByteString string List
.proto

https://protobuf.dev/programming-guides/proto3/

2、服务器端实现

服务器端实例使用java编写

2.1、生成gRPC服务类

pom.xml


<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.0modelVersion>

    <groupId>com.penngogroupId>
    <artifactId>grpc-helloworldartifactId>
    <version>1.0version>

    <properties>
        <maven.compiler.source>11maven.compiler.source>
        <maven.compiler.target>11maven.compiler.target>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    properties>
    <dependencies>
        <dependency>
            <groupId>io.grpcgroupId>
            <artifactId>grpc-netty-shadedartifactId>
            <version>1.59.0version>
            <scope>runtimescope>
        dependency>
        <dependency>
            <groupId>io.grpcgroupId>
            <artifactId>grpc-protobufartifactId>
            <version>1.59.0version>
        dependency>
        <dependency>
            <groupId>io.grpcgroupId>
            <artifactId>grpc-stubartifactId>
            <version>1.59.0version>
        dependency>
        <dependency> 
            <groupId>org.apache.tomcatgroupId>
            <artifactId>annotations-apiartifactId>
            <version>6.0.53version>
            <scope>providedscope>
        dependency>
    dependencies>
    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.mavengroupId>
                <artifactId>os-maven-pluginartifactId>
                <version>1.7.1version>
            extension>
        extensions>
        <plugins>
            
            <plugin>
                <groupId>org.xolstice.maven.pluginsgroupId>
                <artifactId>protobuf-maven-pluginartifactId>
                <version>0.6.1version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:3.24.0:exe:${os.detected.classifier}protocArtifact>
                    <pluginId>grpc-javapluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.59.0:exe:${os.detected.classifier}pluginArtifact>
                configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compilegoal>
                            <goal>compile-customgoal>
                        goals>
                    execution>
                executions>
            plugin>
        plugins>
    build>
    <repositories>
        <repository>
            <id>alimavenid>
            <name>Maven Aliyun Mirrorname>
            <url>https://maven.aliyun.com/repository/centralurl>
        repository>
    repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>publicid>
            <name>aliyun nexusname>
            <url>https://maven.aliyun.com/nexus/content/groups/public/url>
            <releases>
                <enabled>trueenabled>
            releases>
            <snapshots>
                <enabled>falseenabled>
            snapshots>
        pluginRepository>
    pluginRepositories>
project>

命令行下执行gRPC的java代码

mvn compile

自动扫描代码目中src/main/proto/helloworld.proto下的proto文件,自动生成gRPC相关代码到target/generated-sources/protobuf目录下。
gRPC Java、Go、PHP使用例子_第1张图片

2.2、Java服务器端实现

HelloServer.java

package com.penngo;

import com.penngo.grpc.GreeterGrpc;
import com.penngo.grpc.HelloReply;
import com.penngo.grpc.HelloRequest;
import io.grpc.Grpc;
import io.grpc.InsecureServerCredentials;
import io.grpc.Server;
import io.grpc.stub.StreamObserver;
import java.io.IOException;

public class HelloServer {
    public static void main(String[] args) throws IOException, InterruptedException {
        int port = 50051;
        Server server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create())
                .addService(new GreeterImpl())
                .build()
                .start();

        Runtime.getRuntime().addShutdownHook(new Thread(()->{
            System.err.println("*** shutting down gRPC server since JVM is shutting down");
            stopServer(server);
            System.err.println("*** server shut down");
        }));
        server.awaitTermination();
    }

    private static void stopServer(Server server) {
        if (server != null) {
            server.shutdown();
        }
    }

    static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
        @Override
        public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
            System.out.println("收到客户端消息:" + req.getName());
            String msg = "我是Java Server";
            System.out.println("回复客户端消息:" + msg);
            HelloReply reply = HelloReply.newBuilder().setMessage("你好!" + msg).build();
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
        }

        @Override
        public void sayHelloAgain(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
            System.out.println("再次收到客户端消息:" + req.getName());
            String msg = "我是Java Server2";
            System.out.println("再次回复客户端消息:" + msg);
            HelloReply reply = HelloReply.newBuilder().setMessage(msg).build();
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
        }
    }
}

https://github.com/protocolbuffers/protobuf/releases

3、java、go、php客户端实现

3.1、Java客户端实现

HelloClient.java

package com.penngo;

import com.penngo.grpc.GreeterGrpc;
import com.penngo.grpc.HelloReply;
import com.penngo.grpc.HelloRequest;
import io.grpc.Grpc;
import io.grpc.InsecureChannelCredentials;
import io.grpc.ManagedChannel;

import java.util.concurrent.TimeUnit;

public class HelloClient {
    public static void main(String[] args) throws InterruptedException {
        String host = "localhost";
        int port = 50051;
        ManagedChannel managedChannel = Grpc.newChannelBuilderForAddress(host, port, InsecureChannelCredentials.create()).build();
        GreeterGrpc.GreeterBlockingStub blockingStub = GreeterGrpc.newBlockingStub(managedChannel);
        String msg1 = "我是java client";
        System.out.println("向服务器端发送消息:" + msg1);
        HelloRequest helloRequest1 = HelloRequest.newBuilder().setName(msg1).build();
        HelloReply reply1 = blockingStub.sayHello(helloRequest1);
        System.out.println("收到服务器端消息:" + reply1.getMessage());

        String msg2 = "我是java client2";
        System.out.println("再次向服务器端发送消息:" + msg2);
        HelloRequest helloRequest2 = HelloRequest.newBuilder().setName(msg2).build();
        HelloReply reply2 = blockingStub.sayHelloAgain(helloRequest2);
        System.out.println("再次收到服务器端消息:" + reply2.getMessage());


        managedChannel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
    }

}

3.2、Go客户端实现

Go的代码生成需要使用protoc.exe来编译helloworld.proto服务文件,生成对应的服务调用代码
下载地址:https://github.com/protocolbuffers/protobuf/releases,当前最新版本为protoc-25.1-win64.zip
解压到目录D:\Program Files\protoc-25.1-win64\bin,需要把这个目录添加到环境变量PATH当中。

安装protocol编译器的Go插件

$ go install google.golang.org/protobuf/cmd/[email protected]
$ go install google.golang.org/grpc/cmd/[email protected]

执行下边命令生成Go的gRPC代码

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative helloworld/helloworld.proto

gRPC Java、Go、PHP使用例子_第2张图片

编写客户端实现代码

package main

import (
	"context"
	"flag"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	pb "grpctest/helloworld"
	"log"
	"time"
)

var (
	addr = flag.String("addr", "localhost:50051", "the address to connect to")
)

func main() {
	flag.Parse()

	// Set up a connection to the server.
	conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	// Contact the server and print out its response.
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	msg1 := "我是go client"
	log.Printf("向服务器端发送消息: %s", msg1)
	r1, err1 := c.SayHello(ctx, &pb.HelloRequest{Name: msg1})
	if err1 != nil {
		log.Fatalf("could not greet: %v", err1)
	}
	log.Printf("收到服务器端消息:%s", r1.GetMessage())

	msg2 := "我是go client2"
	log.Printf("再次向服务器端发送消息: %s", msg1)
	r2, err2 := c.SayHelloAgain(ctx, &pb.HelloRequest{Name: msg2})

	if err2 != nil {
		log.Fatalf("could not greet: %v", err2)
	}
	log.Printf("再次收到服务器端消息: %s", r2.GetMessage())
}

3.3、PHP客户端实现

安装gRPC的PHP扩展https://pecl.php.net/package/gRPC
当前测试php版本7.3,下载php_grpc-1.42.0-7.3-nts-vc15-x64.zip
php.ini这个文件加入

extension=php_grpc.dll

新建composer.json

{
  "name": "xxs/grpc",
  "require": {
    "grpc/grpc": "^v1.4.0",
    "google/protobuf": "^v3.3.0"
  },
  "autoload":{
    "psr-4":{
      "GPBMetadata\\":"GPBMetadata/",
      "Helloworld\\":"Helloworld/"
    }
  }
}

在composer.json相同目录下执行命令下载依赖库

composer install

安装grpc的php插件,https://github.com/lifenglsf/grpc_for_windows
解压复制到项目下grpc_for_windows/x64/grpc_php_plugin.exe

执行命令生成gRPC代码

protoc --proto_path=. --php_out=. --grpc_out=. --plugin=protoc-gen-grpc=grpc_for_windows/x64/grpc_php_plugin.exe ./helloworld.proto

gRPC Java、Go、PHP使用例子_第3张图片

client.php实现


require dirname(__FILE__) . '/vendor/autoload.php';
//echo dirname(__FILE__) . '/vendor/autoload.php';
function greet($hostname)
{

    $client = new Helloworld\GreeterClient($hostname, [
        'credentials' => Grpc\ChannelCredentials::createInsecure(),
    ]);
    $request = new Helloworld\HelloRequest();

    $msg1 = "我是PHP client";
    $request->setName($msg1);
    echo "向服务器端发送消息: $msg1". PHP_EOL;
    list($response, $status) = $client->SayHello($request)->wait();
    if ($status->code !== Grpc\STATUS_OK) {
        echo "ERROR: " . $status->code . ", " . $status->details . PHP_EOL;
        exit(1);
    }
    echo "收到服务器端消息:".$response->getMessage() . PHP_EOL;

    $msg2 = "我是PHP client2";
    $request->setName($msg2);
    echo "再次向服务器端发送消息: $msg2". PHP_EOL;
    list($response, $status) = $client->SayHelloAgain($request)->wait();
    if ($status->code !== Grpc\STATUS_OK) {
        echo "ERROR: " . $status->code . ", " . $status->details . PHP_EOL;
        exit(1);
    }
    echo "再次收到服务器端发送消息:".$response->getMessage() . PHP_EOL;

    $client->close();
}

$hostname = !empty($argv[2]) ? $argv[2] : 'localhost:50051';
greet($hostname);

附件源码

你可能感兴趣的:(java,Go,java,golang,php,gRPC)