本文实现Java和Python之间通过grpc交互,只使用最基本的单项rpc。
一、Java实现grpc
使用idea新建maven项目,项目目录如下
image
项目的pom.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
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">
4.0.0
test
grpc
1.0-SNAPSHOT
io.grpc
grpc-netty-shaded
1.15.0
io.grpc
grpc-protobuf
1.15.0
io.grpc
grpc-stub
1.15.0
kr.motd.maven
os-maven-plugin
1.5.0.Final
org.xolstice.maven.plugins
protobuf-maven-plugin
0.5.1
com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}
grpc-java
io.grpc:protoc-gen-grpc-java:1.15.0:exe:${os.detected.classifier}
src/main/resources/proto
compile
compile-custom
org.apache.maven.plugins
maven-compiler-plugin
1.8
1.8
其中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文件:
image
然后编写服务端代码:
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 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项目目录如下:
image
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这一项也要相同!!