gRPC Java、Go、PHP使用例子
后台-插件-广告管理-内容页头部广告(手机) |
RPC选型入门测试系列文章
【1】GraphQL基础知识与Spring for GraphQL使用教程
【2】gRPC Java、Go、PHP使用例子
【3】Thrift RPC 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
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
1.2、Protobuf基础数据类型
.proto | 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 | int64 | Bignum | long | integer/string | Int64 |
uint32 | uint32 | int | int/long | uint32 | Fixnum or Bignum (as required) | uint | integer | int |
uint64 | uint64 | long | int/long | uint64 | Bignum | ulong | integer/string | Int64 |
sint32 | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
sint64 | int64 | long | int/long | int64 | Bignum | long | integer/string | Int64 |
fixed32 | uint32 | int[2] | int/long[4] | uint32 | Fixnum or Bignum (as required) | uint | integer | int |
fixed64 | uint64 | long[2] | int/long | uint64 | Bignum | ulong | integer/string | Int64 |
sfixed32 | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
sfixed64 | int64 | long | int/long | int64 | Bignum | long | integer/string | Int64 |
bool | bool | boolean | bool | bool | TrueClass/FalseClass | bool | boolean | bool |
string | string | String | str/unicode | string | String (UTF-8) | string | string | String |
bytes | string | ByteString | str (Python 2) bytes (Python 3) | []byte | String (ASCII-8BIT) | ByteString | string | List |
参考自官方:https://protobuf.dev/programming-guides/proto3/
2、服务器端实现
服务器端实例使用java编写
2.1、生成gRPC服务类
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"> <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>- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
命令行下执行gRPC的java代码
mvn compile- 1
自动扫描代码目中src/main/proto/helloworld.proto下的proto文件,自动生成gRPC相关代码到target/generated-sources/protobuf目录下。
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(); } } }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
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); } }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
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/protoc-gen-go@v1.28 $ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2- 1
- 2
执行下边命令生成Go的gRPC代码
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative helloworld/helloworld.proto- 1
编写客户端实现代码
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()) }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
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这个文件加入
- 1
新建composer.json
{ "name": "xxs/grpc", "require": { "grpc/grpc": "^v1.4.0", "google/protobuf": "^v3.3.0" }, "autoload":{ "psr-4":{ "GPBMetadata\\":"GPBMetadata/", "Helloworld\\":"Helloworld/" } } }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
在composer.json相同目录下执行命令下载依赖库
composer install- 1
安装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- 1
client.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);- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
附件源码
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。
在线投稿:投稿 站长QQ:1888636
后台-插件-广告管理-内容页尾部广告(手机) |