gRPC Java、Go、PHP使用例子

文章目录

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

1、Protocol Buffers定义接口

1.1、编写接口服务

protobuf 复制代码
// 定义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基础数据类型

    <th>C++</th>
    <th>Java/Kotlin</th>
    <th>Python</th>
    <th>Go</th>
    <th>Ruby</th>
    <th>C#</th>
    <th>PHP</th>
    <th>Dart</th>
</tr>
<tr>
    <td>double</td>
    
    <td>double</td>
    <td>double</td>
    <td>float</td>
    <td>float64</td>
    <td>Float</td>
    <td>double</td>
    <td>float</td>
    <td>double</td>
</tr>
<tr>
    <td>float</td>
   
    <td>float</td>
    <td>float</td>
    <td>float</td>
    <td>float32</td>
    <td>Float</td>
    <td>float</td>
    <td>float</td>
    <td>double</td>
</tr>
<tr>
    <td>int32</td>
  
    <td>int32</td>
    <td>int</td>
    <td>int</td>
    <td>int32</td>
    <td>Fixnum or Bignum (as required)</td>
    <td>int</td>
    <td>integer</td>
    <td>int</td>
</tr>
<tr>
    <td>int64</td>

    <td>int64</td>
    <td>long</td>
    <td>int/long<sup>[4]</sup></td>
    <td>int64</td>
    <td>Bignum</td>
    <td>long</td>
    <td>integer/string<sup>[6]</sup></td>
    <td>Int64</td>
</tr>
<tr>
    <td>uint32</td>
   
    <td>uint32</td>
    <td>int<sup>[2]</sup></td>
    <td>int/long<sup>[4]</sup></td>
    <td>uint32</td>
    <td>Fixnum or Bignum (as required)</td>
    <td>uint</td>
    <td>integer</td>
    <td>int</td>
</tr>
<tr>
    <td>uint64</td>
 
    <td>uint64</td>
    <td>long<sup>[2]</sup></td>
    <td>int/long<sup>[4]</sup></td>
    <td>uint64</td>
    <td>Bignum</td>
    <td>ulong</td>
    <td>integer/string<sup>[6]</sup></td>
    <td>Int64</td>
</tr>
<tr>
    <td>sint32</td>
   
    <td>int32</td>
    <td>int</td>
    <td>int</td>
    <td>int32</td>
    <td>Fixnum or Bignum (as required)</td>
    <td>int</td>
    <td>integer</td>
    <td>int</td>
</tr>
<tr>
    <td>sint64</td>
    
    <td>int64</td>
    <td>long</td>
    <td>int/long<sup>[4]</sup></td>
    <td>int64</td>
    <td>Bignum</td>
    <td>long</td>
    <td>integer/string<sup>[6]</sup></td>
    <td>Int64</td>
</tr>
<tr>
    <td>fixed32</td>
  
    <td>uint32</td>
    <td>int<sup>[2]</sup></td>
    <td>int/long<sup>[4]</sup></td>
    <td>uint32</td>
    <td>Fixnum or Bignum (as required)</td>
    <td>uint</td>
    <td>integer</td>
    <td>int</td>
</tr>
<tr>
    <td>fixed64</td>
  
    <td>uint64</td>
    <td>long<sup>[2]</sup></td>
    <td>int/long<sup>[4]</sup></td>
    <td>uint64</td>
    <td>Bignum</td>
    <td>ulong</td>
    <td>integer/string<sup>[6]</sup></td>
    <td>Int64</td>
</tr>
<tr>
    <td>sfixed32</td>
   
    <td>int32</td>
    <td>int</td>
    <td>int</td>
    <td>int32</td>
    <td>Fixnum or Bignum (as required)</td>
    <td>int</td>
    <td>integer</td>
    <td>int</td>
</tr>
<tr>
    <td>sfixed64</td>
   
    <td>int64</td>
    <td>long</td>
    <td>int/long<sup>[4]</sup></td>
    <td>int64</td>
    <td>Bignum</td>
    <td>long</td>
    <td>integer/string<sup>[6]</sup></td>
    <td>Int64</td>
</tr>
<tr>
    <td>bool</td>
   
    <td>bool</td>
    <td>boolean</td>
    <td>bool</td>
    <td>bool</td>
    <td>TrueClass/FalseClass</td>
    <td>bool</td>
    <td>boolean</td>
    <td>bool</td>
</tr>
<tr>
    <td>string</td>
    
    <td>string</td>
    <td>String</td>
    <td>str/unicode<sup>[5]</sup></td>
    <td>string</td>
    <td>String (UTF-8)</td>
    <td>string</td>
    <td>string</td>
    <td>String</td>
</tr>
<tr>
    <td>bytes</td>
    
    <td>string</td>
    <td>ByteString</td>
    <td>str (Python 2)<br>bytes (Python 3)</td>
    <td>[]byte</td>
    <td>String (ASCII-8BIT)</td>
    <td>ByteString</td>
    <td>string</td>
    <td>List
        <int></int>
    </td>
</tr>
</tbody>
.proto

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

2、服务器端实现

服务器端实例使用java编写

2.1、生成gRPC服务类

pom.xml

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

    <groupId>com.penngo</groupId>
    <artifactId>grpc-helloworld</artifactId>
    <version>1.0</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <version>1.59.0</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>1.59.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.59.0</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.7.1</version>
            </extension>
        </extensions>
        <plugins>
            <!-- grpc代码生成插件 -->
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.6.1</version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:3.24.0:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.59.0:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>alimaven</id>
            <name>Maven Aliyun Mirror</name>
            <url>https://maven.aliyun.com/repository/central</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>https://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>

命令行下执行gRPC的java代码

bash 复制代码
mvn compile

自动扫描代码目中src/main/proto/helloworld.proto下的proto文件,自动生成gRPC相关代码到target/generated-sources/protobuf目录下。

2.2、Java服务器端实现

HelloServer.java

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

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插件

bash 复制代码
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2

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

bash 复制代码
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative helloworld/helloworld.proto

编写客户端实现代码

go 复制代码
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

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

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

bash 复制代码
composer install

安装grpc的php插件,https://github.com/lifenglsf/grpc_for_windows

解压复制到项目下grpc_for_windows/x64/grpc_php_plugin.exe

执行命令生成gRPC代码

bash 复制代码
protoc --proto_path=. --php_out=. --grpc_out=. --plugin=protoc-gen-grpc=grpc_for_windows/x64/grpc_php_plugin.exe ./helloworld.proto

client.php实现

php 复制代码
<?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);

附件源码

相关推荐
john_hjy28 分钟前
7. 机器人项目
java·前端·javascript
那你为何对我三笑留情30 分钟前
一、Spring Boot集成Spring Security之自动装配
java·spring boot·spring·spring security
鱼跃鹰飞34 分钟前
大厂面试真题-介绍以下Docker的Overlay网络
java·网络·docker·容器·面试·职场和发展
无尽的大道3 小时前
深入剖析 Android Lifecycle:构建高效稳定的应用
android·java
乌夷4 小时前
将 Java 对象自动转换为 XML 字符串
xml·java·开发语言
逸狼4 小时前
【JavaEE初阶】文件IO(下)
java·java-ee
Ylucius5 小时前
常见服务器大全----都是什么?又有何作用?区别联系是什么?---web,应用,数据库,文件,消息队列服务器,Tomat,Nginx,vite.....
java·前端·javascript·chrome·学习·node.js·express
茜茜西西CeCe5 小时前
移动技术开发:RecyclerView瀑布流水果列表
android·java·安卓·android-studio·recycleview·移动技术开发
熙曦Sakura6 小时前
【C/C++】错题记录(一)
java·c语言·c++
无极程序员7 小时前
读取到json数据拿出来,修改后重新写入json文件
android·java·开发语言·后端·json·php