1.1 RPC 框架原理

RPC 框架的目标就是让远程服务调用更加简单、透明,RPC 框架的目标就是让远程服务调用更加简单、透明,RPC 框架负责屏蔽底层的传输方式(TCP 或者 UDP)、序列化方式(XML/Json/ 二进制)和通信细节。服务调用者可以像调用本地接口一样调用远程的服务提供者,而不需要关心底层通信细节和调用过程。

原理流程如下:

2.gRPC

        gRPC 是由 Google 开发并开源的一种语言中立的 RPC 框架,当前支持 C、Java 和 Go 语言,其中 C 版本支持 C、C++、Node.js、C# 等。

2.1. gRPC 服务端创建

下面以搭建一个node服务为例介绍gRPC的使用(windows环境):

首先安装node.js(安装地址:https://nodejs.org/en/download/)

2.1.1在任意磁盘下建立文件夹rgpc-node,命令提示符敲:npm init 建立项目

2.1.2安装protoc以及grpc插件
        这个用npm直接安装 
       npm install grpc-tools --save-dev
       npm install google-protobuf --save
       npm install grpc --save
      在./node_modules/grpc-tools/bin下,你会找到 protoc.exe 和 grpc_node_plugin.exe两个文件。

如果在npm install grpc-tools --save-dev 安装时node-pre-spy 安装不成功是,下面会有 package.json文件附上,把package.json里的依赖拷进到你的依赖里去,npm install 即可,安装 以上工具的目的是我们要使用.proto文件并使用protoc 进行编译

package.json

{
  "name": "grpc-node",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@grpc/proto-loader": "^0.1.0",
    "async": "^1.5.2",
    "google-protobuf": "^3.0.0",
    "grpc": "^1.11.0",
    "lodash": "^4.6.1",
    "minimist": "^1.2.0"
  }
}

以上都安装好了,开始创建一个  HelloWorldService.proto文件

syntax = "proto3";

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

package hellostreamingworld;

// The greeting service definition.
service MultiGreeter {
  // Sends multiple greetings
  rpc sayHello (HelloRequest) returns (stream HelloReply) {}
}

// The request message containing the user's name and how many greetings
// they want.
message HelloRequest {
  string name = 1;
  string num_greetings = 2;
}

// A response message containing a greeting
message HelloReply {
  string message = 1;
}

 运行编译命令
./node_modules/grpc-tools/bin/protoc --js_out=import_style=commonjs,binary:./ --plugin=protoc-gen-grpc=./node_modules/grpc-tools/bin/grpc_node_plugin.exe --grpc_out=./ HelloWorldService.proto
运行完成后,会生成HelloWorldService_grpc_pb.js 和 HelloWorldServer_pb.js两个文件。(这一步要不要无关大局,只是将.proto文件转成相应的.js文件,.proto文件一样可以引入)

如果是你使用了编译命令生成了两个相应的.js文件

下面建立server.js文件(前提是你编译成功)

var services = require('./HelloWorldService_grpc_pb.js');
var messages = require('./HelloWorldService_pb.js');
var grpc = require('grpc')
var hello = function(call, callback) {
  var response = new messages.HelloResponse();
  response.setHellostring("hello," + call.request.getName());
  callback(null, response);
}
var server = new grpc.Server();
server.addService(
  services.HelloWorldServiceService,
  {
    hello:hello
  }
);
server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
server.start(function(err,data){
  console.log(err);
  console.log(data);
});

紧接着是建立client.js文件(前提是你编译成功)

var grpc = require('grpc');
var messages = require('./HelloWorldService_pb.js');
var services = require('./HelloWorldService_grpc_pb.js')
var request = new messages.HelloRequest();
request.setName('world');
var client = new services.HelloWorldServiceClient(
  'localhost:50051',
  grpc.credentials.createInsecure()
);
client.hello(request, function(err,data){
  if(err){
    console.error(err);
  }
  console.log(data);
  console.log(data.getHellostring());
})

倘若没有将.proto文件编译成相应的.js文件

Node.js 的类库在运行时加载 .proto 中的客户端存根并动态生成服务描述符。

要加载一个 .proto 文件,只需要 require gRPC 类库,然后使用它的 load() 方法:

步骤同上

1建立server.js文件

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

var grpc = require('grpc');
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;

/**
 * Implements the SayHello RPC method.
 */
function sayHello(call, callback) {
  callback(null, {message: 'Hello ' + call.request.name});
}

/**
 * Starts an RPC server that receives requests for the Greeter service at the
 * sample server port
 */
function main() {
  var server = new grpc.Server();
  server.addService(hello_proto.Greeter.service, {sayHello: sayHello});
  server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
  server.start();
}

main();

 建立client.js文件

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

var grpc = require('grpc');
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('localhost:50051',
                                       grpc.credentials.createInsecure());
  var user;
  if (process.argv.length >= 3) {
    user = process.argv[2];
  } else {
    user = 'world';
  }
  client.sayHello({name: user}, function(err, response) {
    console.log('Greeting:', response.message);
  });
}

main();

接着就是怎么运行了,首先在你的项目根目录cmd 直接运行node server.js

接着仍然是那个根目录cmd 直接运行node client.js 你会看到打印出Greeting: hello world