Java
getStuNo.proto
syntax = "proto3"; option java_multiple_files = true; option java_package = "io.grpc.examples.getstuno"; option java_outer_classname = "GetStuNoProto"; option objc_class_prefix = "GSN"; package getstuno; service GetStuNoService { rpc getMsg (StuNoRequest) returns (StuNoResponse){} } message StuNoRequest { string name = 1; } message StuNoResponse { string number = 1; }
protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储。这里使用proto文件用于生成gRPC所需要的框架。生成方式参照https://blog.csdn.net/qq_29319189/article/details/93539198
GetStuNoServer.java
package getstuno; import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.examples.getstuno.GetStuNoServiceGrpc; import io.grpc.examples.getstuno.StuNoResponse; import io.grpc.examples.getstuno.StuNoRequest; import io.grpc.stub.StreamObserver; import java.io.IOException; import java.util.logging.Logger; /** * Server that manages startup/shutdown of a {@code Greeter} server. */ public class GetStuNoServer { private static final Logger logger = Logger.getLogger(GetStuNoServer.class.getName()); private Server server; private void start() throws IOException { /* The port on which the server should run */ int port = 50051; server = ServerBuilder.forPort(port) .addService(new GetStuNoServiceImpl()) .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"); GetStuNoServer.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 GetStuNoServer server = new GetStuNoServer(); server.start(); server.blockUntilShutdown(); } static class GetStuNoServiceImpl extends GetStuNoServiceGrpc.GetStuNoServiceImplBase { @Override public void getMsg(StuNoRequest req, StreamObserver<StuNoResponse> responseObserver) { String number = "0000"; logger.info("Received name: " + req.getName()); if (req.getName().equals("爱丽丝")) { number = "1234"; } StuNoResponse reply = StuNoResponse.newBuilder().setNumber(number).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); } } }
Server端重点实现提供的服务
GetStuNoClient.java
package getstuno; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; import io.grpc.examples.getstuno.GetStuNoServiceGrpc; import io.grpc.examples.getstuno.StuNoResponse; import io.grpc.examples.getstuno.StuNoRequest; 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 GetStuNoServer}. */ public class GetStuNoClient { private static final Logger logger = Logger.getLogger(GetStuNoClient.class.getName()); private final ManagedChannel channel; private final GetStuNoServiceGrpc.GetStuNoServiceBlockingStub blockingStub; /** Construct client connecting to GetStuNo server at {@code host:port}. */ public GetStuNoClient(String host, int port) { this(ManagedChannelBuilder.forAddress(host, port) // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid // needing certificates. .usePlaintext() .build()); } /** Construct client for accessing HelloWorld server using the existing channel. */ GetStuNoClient(ManagedChannel channel) { this.channel = channel; blockingStub = GetStuNoServiceGrpc.newBlockingStub(channel); } public void shutdown() throws InterruptedException { channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); } /** Say hello to server. */ public void greet(String name) { StuNoRequest request = StuNoRequest.newBuilder().setName(name).build(); StuNoResponse response; try { response = blockingStub.getMsg(request); } catch (StatusRuntimeException e) { logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); return; } logger.info("Client received: " + response.getNumber()); } /** * 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 { GetStuNoClient client = new GetStuNoClient("localhost", 50051); try { /* Access a service running on the local machine on port 50051 */ String user = "爱丽丝"; if (args.length > 0) { user = args[0]; /* Use the arg as the name to greet if provided */ } client.greet(user); } finally { client.shutdown(); } } }
Client端向Server端请求服务
Python
getStuNo.proto
syntax = "proto3"; package getstuno; service GetStuNoService { rpc getMsg (StuNoRequest) returns (StuNoResponse){} } message StuNoRequest { string name = 1; } message StuNoResponse { string number = 1; }
Python与Java的proto文件基本相同,重点在于package必须相同,否则当提供名称、类型相同的service和message时仍然无法沟通。python利用proto生成grpc框架的方法参照:
https://www.cnblogs.com/zongfa/p/12218341.html
server.py
import grpc import getStuNo_pb2 import getStuNo_pb2_grpc from concurrent import futures import time _ONE_DAY_IN_SECONDS = 60 * 60 * 24 class GetStuNoServicer(getStuNo_pb2_grpc.GetStuNoServiceServicer): def getMsg(self, request, context): print("Received name: %s" % request.name) if request.name == '爱丽丝': number = '1234' else: number = '0000' return getStuNo_pb2.StuNoResponse(number=number) def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) getStuNo_pb2_grpc.add_GetStuNoServiceServicer_to_server(GetStuNoServicer(), 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()
client.py
import grpc import getStuNo_pb2 import getStuNo_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 = getStuNo_pb2_grpc.GetStuNoServiceStub(channel) response = stub.getMsg(getStuNo_pb2.StuNoRequest(name='爱丽丝')) print("Client received: " + response.number) if __name__ == '__main__': run()
python端的代码较为精简。
此时,保证了java和python端的gRPC提供的gRPC服务名,服务传输的变量名、类型,服务使用的端口相同。先启动java或python任意一个server端,再启动java或python任意一个client端,都可以正确提供gRPC服务。