IDEA中基于web项目手写一个grpc
1、要定义protocol buffers,文件以.proto结尾,文件中定义message,message中定义成员变量(类型以及对应的序号),序号从1开始;定义服务(Service),服务中定义rpc的request和response。request和response分为流式和非流式,所以rpc可以分为四种类型。另外文件要指定编译的版本,编译后java类的包名,如果要用其他.proto文件中定义的消息,需要import进行导入。
proto语法:
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";
package helloworld;
// 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;
}
2、mvn编译可以让.proto文件生成对应的java类,这样就可以在java程序中使用。编译后,生成的java类在target文件夹下(IDEA开发工具,mvn进行依赖管理),proto文件每一个定义的Service,就会对应一个同名加上Grpc后缀的java类,那么问题转化为如何使用这样一个后缀为Grpc的类(客户端和服务端如何让编写)。
写客户端:
Skip to content
Why GitHub?
Team
Enterprise
Explore
Marketplace
Pricing
Search
Sign in
Sign up
grpc
/
grpc-java
5518.2k2.8k
Code
Issues
433
Pull requests
63
Actions
Projects
1
Security
Insights
grpc-java/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java /
@ejona86
ejona86 examples: Allow passing target and simplify lifecycle
…
Latest commit 5b7f5b8 on 23 Jan
History
8 contributors
@ejona86@carl-mastrangelo@dapengzhang0@nmittler@steverao@zhangkun83@punkeel@jorgheymans
99 lines (90 sloc) 3.74 KB
/*
* Copyright 2015 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.examples.helloworld;
import io.grpc.Channel;
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 GreeterGrpc.GreeterBlockingStub blockingStub;
/** Construct client for accessing HelloWorld server using the existing channel. */
public HelloWorldClient(Channel channel) {
// 'channel' here is a Channel, not a ManagedChannel, so it is not this code's responsibility to
// shut it down.
// Passing Channels to code makes code easier to test and makes it easier to reuse Channels.
blockingStub = GreeterGrpc.newBlockingStub(channel);
}
/** 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. The second argument is the target server.
*/
public static void main(String[] args) throws Exception {
String user = "world";
// Access a service running on the local machine on port 50051
String target = "localhost:50051";
// Allow passing in the user and target strings as command line arguments
if (args.length > 0) {
if ("--help".equals(args[0])) {
System.err.println("Usage: [name [target]]");
System.err.println("");
System.err.println(" name The name you wish to be greeted by. Defaults to " + user);
System.err.println(" target The server to connect to. Defaults to " + target);
System.exit(1);
}
user = args[0];
}
if (args.length > 1) {
target = args[1];
}
// Create a communication channel to the server, known as a Channel. Channels are thread-safe
// and reusable. It is common to create channels at the beginning of your application and reuse
// them until the application shuts down.
ManagedChannel channel = ManagedChannelBuilder.forTarget(target)
// Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
// needing certificates.
.usePlaintext()
.build();
try {
HelloWorldClient client = new HelloWorldClient(channel);
client.greet(user);
} finally {
// ManagedChannels use resources like threads and TCP connections. To prevent leaking these
// resources the channel should be shut down when it will no longer be used. If it may be used
// again leave it running.
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
}
}
}
可以看到:(1)编写client的时候,定义了一个: private final GreeterGrpc.GreeterBlockingStub blockingStub;
这个变量是一个存根,用于本地调用,并且还是一个Blocking(阻塞的)的存根,或者说是同步调用的存根,要等待服务端返回结果,才会接着执行下面的逻辑。
(2)blockingStub = GreeterGrpc.newBlockingStub(channel),构造方法传入的是Channel,通道,提供ip和端口号进行rpc通信。
(3)利用stub来调用rpc方法,返回值是定义的response类。像上面的sayHello方法
编写服务端:
package io.grpc.examples.helloworld;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
/**
* Server that manages startup/shutdown of a {@code Greeter} server.
*/
public class HelloWorldServer {
private static final Logger logger = Logger.getLogger(HelloWorldServer.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 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");
try {
HelloWorldServer.this.stop();
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
System.err.println("*** server shut down");
}
});
}
private void stop() throws InterruptedException {
if (server != null) {
server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
}
}
/**
* 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 {
@Override
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
}
可以看到如何编写服务端:(1)定义一个类,实现GreeterGrpc.GreeterImplBase,重写方法sayHello,返回自定义的返回值。
另外如果只是想在rpc是无参数的,可以通过先
import "google/protobuf/empty.proto";(不是特别确定在这个proto文件中)
再使用
google.protobuf.Empty类型,也可以使用proto的boolean类型,google.protobuf.BoolValue
比如:
rpc deleteAgent (google.protobuf.Empty) returns (google.protobuf.BoolValue);
另外关于服务端中的StreamObserver,参考:https://blog.csdn.net/u010900754/article/details/106203724。
关于简单的grpc例子,参考:http://doc.oschina.net/grpc?t=60134#client

浙公网安备 33010602011771号