gRPC的4种通信方式在node中实现

1. gRPC简介

RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型。使用的时候客户端调用server端提供的接口就像是调用本地的函数一样。

gRPC = google开发的RPC协议
优点:
1、接口有更严格的约束
2、更安全
3、性能更好 。
这3个优点来源于gRPC使用的protobuf(一种数据传输格式和规范)

参考相关连接
gRPC详解
Google Protobuf简明教程

2. gRPC的4种通讯方式

  1. 简单gRPC调用:客户端通过stub发起请求,等待服务端callback()返回结果,就像本地调用一样
  2. 服务端流式调用:客户端发起一次请求,服务端不是返回一个结果,而是将一组结果通过流call()返回
  3. 客户端流式调用:客户端发起一组请求write(),on(),服务端等到客户端所有请求发送完毕,接收到客户端的end()调用,此时服务端callback()发送一次结果给客户端
  4. 客户端服务端双向流:客户端和服务端双向流互不干预,可各种按照自己的顺序消费处理,比如服务端可以选择每次接受客户端一个请求就write(),on()返回一个结果,也可以选择等客户端所有请求发送完毕收到客户端的end()调用再把所有的返回结果一次性call()返回给客户端

3. gRPC在node.js中实现

3.0 node.js环境配置

需要安装npm i @grpc/grpc-js, @grpc/proto-loader, google-protobuf, grpc-tools, async
或者以下package.json文件直接安装npm install

这里需要注意安装的是@grpc/grpc-js而不是grpc,如果安装的是grpc,只需将后续文件中的var grpc = require(’@grpc/grpc-js’);改为var grpc = require(‘grpc’);,同时改变server.bindAsync()为server.bind()即可。

{
  "name": "grpc-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@grpc/grpc-js": "^1.2.12",
    "@grpc/proto-loader": "^0.6.0",
    "async": "^3.2.0",
    "google-protobuf": "*",
    "grpc-tools": "^1.11.1",
    "lodash": "^4.17.21"
  }
}

3.1 定义protobuf的文件.proto

根目录创建proto文件夹并创建helloworld.proto文件

syntax = "proto3";

// option java_package = "ex.grpc";
// option objc_class_prefix = "HSW";

package helloworld;

service Greeter {
  // 简单gRPC调用
  rpc sayHelloSimple (HelloRequest) returns (HelloReply) {}

  // 服务端流式调用
  rpc sayHelloServer (HelloRequest) returns (stream HelloReply) {}

  // 客户端流式调用
  rpc sayHelloClient (stream HelloRequest) returns (HelloReply) {}

  // 客户端服务端双向流
  rpc sayHelloDouble (stream HelloRequest) returns (stream HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

3.2 简单gRPC调用

3.2.1 服务端

var PROTO_PATH = __dirname + '/protos/helloworld.proto';

var grpc = require('@grpc/grpc-js');
var protoLoader = require('@grpc/proto-loader');
var packageDefinition = protoLoader.loadSync(
    PROTO_PATH,
    {keepCase: true,
     longs: String,
     enums: String,
     defaults: true,
     oneofs: true
    });
var hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld;

// 简单gRPC调用
function sayHelloSimple(call, callback) {
  callback(null, {message: 'Hello ' + call.request.name});
}

async function main() {
  var server = new grpc.Server();
  server.addService(hello_proto.Greeter.service, {sayHelloSimple: sayHelloSimple});
  await new Promise((resolve, reject) => {
    server.bindAsync(
        `0.0.0.0:50051`,
        grpc.ServerCredentials.createInsecure(),
        (err, result) => (err ? reject(err) : resolve(result))
    );
  });
  
  server.start();
  // 显示是否启动成功
  console.log(server.started);
}

main();

3.2.2 客户端

var PROTO_PATH = __dirname + '/protos/helloworld.proto';

var grpc = require('@grpc/grpc-js');
var protoLoader = require('@grpc/proto-loader');
var packageDefinition = protoLoader.loadSync(
    PROTO_PATH,
    {keepCase: true,
     longs: String,
     enums: String,
     defaults: true,
     oneofs: true
    });
var hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld;

function main() {
  var client = new hello_proto.Greeter('0.0.0.0:50051', grpc.credentials.createInsecure());
  client.sayHelloSimple({name: 'World, Eden!!!'}, function(err, response) {
    console.log('Greeting:', response.message);
  });
}

main();

3.2.3 启动结果

依次启动服务端和客户端,分别在terminal中出现一下内容,即简单gRPC通信完成

// 服务端
>>> node server.js
true
// 客户端
>>> node client.js
Greeting: Hello World, Eden!!!

3.3 流式gRPC调用

另外三种方式均为流式,已双向流式通信为例进行介绍,在proto中的方法为 rpc sayHelloDouble (stream HelloRequest) returns (stream HelloReply) {}

3.3.1 服务端

服务端新增客户端服务端双向流方法,同时注册多个service

var PROTO_PATH = __dirname + '/protos/helloworld.proto';

var grpc = require('@grpc/grpc-js');
var protoLoader = require('@grpc/proto-loader');
var packageDefinition = protoLoader.loadSync(
    PROTO_PATH,
    {keepCase: true,
     longs: String,
     enums: String,
     defaults: true,
     oneofs: true
    });
var hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld;

// 简单gRPC调用
function sayHelloSimple(call, callback) {
  callback(null, {message: 'Hello ' + call.request.name});
}

// 服务端流式调用
function sayHelloServer(call, callback) {

}

// 客户端流式调用
function sayHelloClient(call, callback) {

}

// 客户端服务端双向流
function sayHelloDouble(call, callback) {
  callback(null, {message: 'Hello ' + call.request.name});
}

async function main() {
  var server = new grpc.Server();
  server.addService(hello_proto.Greeter.service, {sayHelloSimple: sayHelloSimple, sayHelloServer: sayHelloServer, sayHelloClient: sayHelloClient, sayHelloDouble: sayHelloDouble});
  await new Promise((resolve, reject) => {
    server.bindAsync(
        `0.0.0.0:50051`,
        grpc.ServerCredentials.createInsecure(),
        (err, result) => (err ? reject(err) : resolve(result))
    );
  });
  
  server.start();
  // 显示是否启动成功
  console.log(server.started);
}

main();

3.3.2 客户端

var PROTO_PATH = __dirname + '/protos/helloworld.proto';

var grpc = require('@grpc/grpc-js');
var protoLoader = require('@grpc/proto-loader');
var packageDefinition = protoLoader.loadSync(
  PROTO_PATH,
  {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true
  });
var hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld;

function main() {
  var client = new hello_proto.Greeter('0.0.0.0:50051', grpc.credentials.createInsecure());
  client.sayHelloSimple({ name: 'World, Eden!!!' }, function (err, response) {
    console.log('Greeting:', response.message);
  });

  let call = client.sayHelloDouble();

  call.on('data', function (response) {
    console.log('客户端receive:', response);
  });

  call.on('end', function () {
    console.log('服务器发送end,客户端关闭');
  });

  call.write({ name: 'Eden1' });
  call.write({ name: 'Eden2' });
  call.write({ name: 'Eden3' });

  call.end();
}

main();

3.3.3 启动结果

双向流通信中同时包括简单gRPC通信的方法,所以同时包含两个结果

// 服务端
>>> node server.js
true
服务端receive: { name: 'Eden1' }
服务端receive: { name: 'Eden2' }
服务端receive: { name: 'Eden3' }
服务端收到end,给客户端发送end
// 客户端
>>> node client.js
Greeting: Hello World, Eden!!!
客户端receive: { message: 'Hello Eden1' }
客户端receive: { message: 'Hello Eden2' }
客户端receive: { message: 'Hello Eden3' }
服务器发送end,客户端关闭

其他gRPC实战项目
gRPC实战–如何在NodeJS中有效使用gRPC流
该链接主要包括客户端流通信,和服务端流通信,为通讯方式的第2,3种,刚好与本文的第1,4种互补,读者可自行参阅。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
在RSU(Roadside Unit)实现 gRPC 客户端,您可以按照以下步骤进行操作: 1. 在 RSU 的代码项目,首先确保您已经安装了 gRPC 相关的依赖。您可以在项目的构建脚本(如 Maven 或 Gradle)添加 gRPC 的依赖项。 2. 定义您的 gRPC 服务接口。这是一个.proto 文件,其包含了您定义的服务和消息类型。您可以使用 Protocol Buffers(protobuf)来定义接口。 3. 使用 protobuf 编译器生成 gRPC 的客户端代码。通过运行 protobuf 编译器,可以将.proto 文件编译为相应的客户端和服务器代码。生成的代码将提供用于与 gRPC 服务进行通信的接口和方法。 4. 在 RSU 的代码,使用生成的 gRPC 客户端代码来创建并初始化 gRPC 的客户端对象。 5. 使用 gRPC 客户端对象调用远程 gRPC 服务的方法。根据您在.proto 文件定义的接口和方法,使用 gRPC 客户端对象调用相应的方法进行远程调用。 6. 处理 gRPC 服务的响应结果。根据您的业务逻辑,处理来自 gRPC 服务的响应结果,并采取相应的操作。 需要注意的是,要使 gRPC 客户端与相应的 gRPC 服务通信,您需要确保 RSU 和 gRPC 服务之间可以相互连接,并且双方都能够访问彼此。 这是一个大致的步骤,具体实现细节可能会因您所使用的编程语言和框架而有所不同。请确保查阅相关的 gRPC 文档和示例代码,以便更好地理解和实现 gRPC 客户端在 RSU 的功能。 希望这能够帮助您在 RSU 实现 gRPC 客户端!如果您还有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值