// 定义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;
}
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/
服务器端实例使用java编写
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目录下。
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
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);
}
}
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
编写客户端实现代码
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())
}
安装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
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);
附件源码