java和python使用grpc互動
阿新 • • 發佈:2018-12-09
本文實現Java和Python之間通過grpc互動,只使用最基本的單項rpc。
一、Java實現grpc
使用idea新建maven專案,專案目錄如下
專案的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.0</modelVersion> <groupId>test</groupId> <artifactId>grpc</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> <version>1.15.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.15.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.15.0</version> </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:3.5.1-1:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.15.0:exe:${os.detected.classifier}</pluginArtifact> <protoSourceRoot>src/main/resources/proto</protoSourceRoot> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
其中proto檔案如下:
helloworld.proto
syntax = "proto3"; package example; option java_package = "com.zhj.grpc"; option java_outer_classname = "HelloWorldServiceProto"; option java_multiple_files = true; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; }
其中package一定要和後面Python中的package設定的值一樣,,,要不。。。很難受找不出錯
然後在專案的根目錄下編譯:
mvn compile
這時會生成相應的Java檔案:
然後編寫服務端程式碼:
package com.helloworld; //import com import com.zhj.grpc.GreeterGrpc; import com.zhj.grpc.HelloReply; import com.zhj.grpc.HelloRequest; import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.stub.StreamObserver; import java.io.IOException; import java.util.logging.Logger; public class HelloWorldServer { private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName()); /* The port on which the server should run */ private int port = 50051; private Server server; private void start() throws IOException { server = ServerBuilder.forPort(port) .addService( new GreeterImpl()) .build() .start(); logger.info("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"); HelloWorldServer.this.stop(); System.err.println("*** server shut down"); } }); } private void stop() { if (server != null) { server.shutdown(); } } /** * Await termination on the main thread since the grpc library uses daemon threads. */ private void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } } /** * Main launches the server from the command line. */ public static void main(String[] args) throws IOException, InterruptedException { final HelloWorldServer server = new HelloWorldServer(); server.start(); server.blockUntilShutdown(); } static class GreeterImpl extends GreeterGrpc.GreeterImplBase { /** 原子Integer */ // public AtomicInteger count = new AtomicInteger(0); @Override public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) { // System.out.println("call sayHello"); HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); // System.out.println(count.incrementAndGet() + Thread.currentThread().getName()); } } }
客戶端程式碼:
package com.helloworld;
import com.zhj.grpc.GreeterGrpc;
import com.zhj.grpc.HelloReply;
import com.zhj.grpc.HelloRequest;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A simple client that requests a greeting from the {@link HelloWorldServer}.
*/
public class HelloWorldClient {
private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName());
private final ManagedChannel channel;
private final GreeterGrpc.GreeterBlockingStub blockingStub;
/**
* Construct client connecting to HelloWorld server at {@code host:port}.
*/
public HelloWorldClient(String host, int port) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
blockingStub = GreeterGrpc.newBlockingStub(channel);
}
public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
}
/**
* Say hello to server.
*/
public void greet(String name) {
logger.info("Will try to greet " + name + " ...");
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
HelloReply response;
try {
response = blockingStub.sayHello(request);
} catch (StatusRuntimeException e) {
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
return;
}
logger.info("Greeting: " + response.getMessage());
}
/**
* Greet server. If provided, the first element of {@code args} is the name to use in the
* greeting.
*/
public static void main(String[] args) throws Exception {
HelloWorldClient client = new HelloWorldClient("localhost", 50051);
try {
String user = "world";
if (args.length > 0) {
user = args[0];
}
client.greet(user);
} finally {
client.shutdown();
}
}
}
然後先執行服務端,再執行客戶端,客戶端會收到如下資訊:
九月 13, 2018 6:18:43 下午 com.helloworld.HelloWorldClient greet
資訊: Will try to greet world ...
九月 13, 2018 6:18:43 下午 com.helloworld.HelloWorldClient greet
資訊: Greeting: Hello world
Process finished with exit code 0
二、Python實現grpc
grpc安裝:pip install grpcio
grpcbuf相關庫:pip install grpcbuf
編譯工具:pip install grpcio-tools
Python專案目錄如下:
proto檔案(與Java使用的proto檔案相同):
syntax = "proto3";
package example;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
在example目錄下編譯:
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./helloworld.proto
會生成helloworld_pb2_grpc.py和helloworld_pb2.py檔案,下面在client和sever中呼叫這兩個檔案。
服務端:
greeter_server.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import time
import grpc
from concurrent import futures
from example import helloworld_pb2, helloworld_pb2_grpc
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
serve()
客戶端:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
#from __future__ import print_function
import grpc
from example import helloworld_pb2, helloworld_pb2_grpc
def run():
# NOTE(gRPC Python Team): .close() is possible on a channel and should be
# used in circumstances in which the with statement does not fit the needs
# of the code.
with grpc.insecure_channel('localhost:50051') as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
print("Greeter client received: " + response.message)
if __name__ == '__main__':
run()
先執行服務端,再執行客戶端,客戶端顯示:
/home/zhj/.virtualenvs/test4-TkH3JH9C/bin/python /home/zhj/project/grpc/python/client/greeter_client.py
Greeter client received: Hello, you!
Process finished with exit code 0
三、Java和Pythongrpc都已實現,現在可以實現兩種語言之間通訊:
java-server + python-client 或者 python-server + java-client,都會顯示一樣的東西。
再次提示一下,Java和Python使用的proto檔案一定要相同,尤其是package這一項也要相同!!