一、 编写proto文件
1、idea新建java项目,在maven中引入以下依赖:
io.grpc
grpc-netty-shaded
1.42.0
io.grpc
grpc-protobuf
1.42.0
io.grpc
grpc-stub
1.42.0
org.apache.tomcat
annotations-api
6.0.53
provided
com.google.protobuf
protobuf-java
3.9.1
com.alibaba
fastjson
1.2.83
kr.motd.maven
os-maven-plugin
1.6.2
org.xolstice.maven.plugins
protobuf-maven-plugin
0.6.1
com.google.protobuf:protoc:3.17.3:exe:${os.detected.classifier}
grpc-java
io.grpc:protoc-gen-grpc-java:1.42.0:exe:${os.detected.classifier}
compile
compile-custom
2、proto文件
syntax = "proto3";
//生成java类所在的包
option java_package = "com.cn.news.proto";
//生成多个类
option java_multiple_files = false;
//生成外层类类名
option java_outer_classname = "NewsProto";
//包名
package news;
//grpc要调用的service
service NewsService{
//list是方法名,NewsRequest代表传入参数,NewsResponse代表返回响应
rpc list(NewsRequest) returns (NewsResponse){}
}
//请求体
message NewsRequest{
string date = 1;
NewsDetail body = 2;
}
//响应体
message NewsResponse{
//repeated说明是一个集合(数组),数组每一个元素都是News对象
repeated News news = 1;
}
//News新闻实体对象
message News{
//对应java的int
int32 id = 1;
//新闻标题
string title = 2;
//新闻内容
string content = 3;
//对应java的long
int64 createTime = 4;
}
message NewsDetail{
//1表示热点新闻 2表示普通新闻
int32 msgType = 1;
//0未读 1-已读
int32 msgStatus = 2;
}
3. 编译并生成java文件
二、 编写grpc服务端
1、实现 NewsServiceGrpc.NewsServiceImplBase 接口,提供服务方法调用
package com.cn.news.service;
import com.cn.news.proto.NewsProto;
import com.cn.news.proto.NewsServiceGrpc;
import io.grpc.stub.StreamObserver;
/**
* description: NewService
* date: 23.4.12 15:52
* author: cn_yaojin
* version: 1.0
*/
public class NewService extends NewsServiceGrpc.NewsServiceImplBase {
@Override
public void list(NewsProto.NewsRequest request, StreamObserver responseObserver) {
String date = request.getDate();
System.out.println("收到客户端请求了,时间:" + date + ",参数体:" + request.getBody().getMsgType());
NewsProto.NewsResponse newList = null;
try {
NewsProto.NewsResponse.Builder newListBuilder = NewsProto.NewsResponse.newBuilder();
String title = "";
if (request.getBody().getMsgType() == 1) {
title = "实时热点";
} else if (request.getBody().getMsgType() == 2) {
title = "精准扶贫";
} else {
title = "为人民服务";
}
NewsProto.News news = NewsProto.News.newBuilder()
.setId(request.getBody().getMsgType())
.setTitle(title)
.setContent(request.getBody().getMsgType() + ":" + title)
.setCreateTime(System.currentTimeMillis())
.build();
newListBuilder.addNews(news);
newList = newListBuilder.build();
} catch (Exception e) {
e.printStackTrace();
responseObserver.onError(e);
} finally {
responseObserver.onNext(newList);
}
responseObserver.onCompleted();
}
}
2、 grpc服务端,启动
package com.cn.news.service;
import io.grpc.Server;
import io.grpc.ServerBuilder;
/**
* description: GRpcServer
* date: 23.4.12 16:29
* author: cn_yaojin
* version: 1.0
*/
public class GRpcServer {
public static void main(String[] args) {
try {
Server server = ServerBuilder.forPort(1031).addService(new NewService()).build().start();
System.out.println("服务已启动,端口:" + server.getPort());
server.awaitTermination();
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、 编写grpc客户端,启动
package com.cn.news.service;
import com.cn.news.proto.NewsProto;
import com.cn.news.proto.NewsServiceGrpc;
import io.grpc.Channel;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* description: GRpcClient
* date: 23.4.12 16:32
* author: cn_yaojin
* version: 1.0
*/
public class GRpcClient {
private NewsServiceGrpc.NewsServiceBlockingStub newsServiceImplBase;
public GRpcClient(Channel channel) {
this.newsServiceImplBase = NewsServiceGrpc.newBlockingStub(channel);
}
public static void main(String[] args) {
//初始化client与服务端的连接
ManagedChannel channel = ManagedChannelBuilder.forTarget("127.0.0.1:1031")
.usePlaintext()
.build();
GRpcClient gRpcClient = new GRpcClient(channel);
//定时任务模拟提交数据
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//以下是构造请求参数
NewsProto.NewsDetail.Builder detail = NewsProto.NewsDetail.newBuilder();
long t = System.currentTimeMillis();
if (t % 5 == 0) {
detail.setMsgType(1);
} else if (t % 5 == 1) {
detail.setMsgType(3);
} else {
detail.setMsgType(2);
}
detail.setMsgStatus(0);
NewsProto.NewsRequest request = NewsProto.NewsRequest
.newBuilder()
.setDate(t + "")
.setBody(detail.build())
.build();
gRpcClient.list(request);
}
}, 10, 30, TimeUnit.SECONDS);
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 调用grpc的提供的服务(此处调用NewService下的list方法)
*
* @param request
*/
public void list(NewsProto.NewsRequest request) {
try {
NewsProto.NewsResponse response = newsServiceImplBase.list(request);
List list = response.getNewsList();
if (list != null) {
for (NewsProto.News t : list) {
System.out.println(String.format("收到服务端响应了,标题:%s,内容:%s,时间:%s", t.getTitle(), t.getContent(), t.getCreateTime()));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
四、启动后的运行示例
五、 编写node客户端
const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');
//以下proto文件与当前的index.js在同一个目录下
const PROTO_PATH = 'helloworld.proto';
const packageDefinition = protoLoader.loadSync(PROTO_PATH);
const hello_proto = grpc.loadPackageDefinition(packageDefinition).news;
function main() {
const client = new hello_proto.NewsService('127.0.0.1:1031',
grpc.credentials.createInsecure());
var detail={
msgType:2,
msgStatus:2
};
var user={
date:123123123123,
body: detail
};
client.list(user, function (err, response) {
var items = response.news
console.log('Greeting:', items);
});
}
main();