我的环境:
ubuntu:16.04(其他系统对应命令需要稍作修改)
node :8.1.2(4.0以上即可)
首先,创建两个目录 myclient 和 myserver,分别存放grpc的客户端和服务端,命令如下:
mkdir myclient
mkdir myserver
首先,进入myserver中,使用 npm init 进行初始化
cd myserver && npm init
然后安装grpc的依赖包
npm install grpc
编写my.proto文件
syntax = "proto3"; //指定协议版本
package myservices;
service assetService{ //定义服务名
rpc getAsset(assetRequest) returns (assetResponse){} //声明一个方法,使用rpc 关键字声明一个getAsset方法,该方法需要传入参数 assetRequest,会返回一个结果assetResponse
}
message assetRequest{ //声明方法中参数的类型
}
message assetResponse{ //声明返回结果的类型
string message = 1;
}
对proto中代码有疑问,可以翻阅一下proto3文档,这个链接需要翻墙,不能翻墙的同学可以百度搜一下proto3的中文文档。
然后开始写服务端的代码了,myserver.js
import grpc from 'grpc' //引入grpc
const PROTO_PATH = __dirname+'/my.proto' //定义.proto文件的路径,我的.proto文件在根目录下,所以写成这样
const myProto = grpc.load(PROTO_PATH).myservices
// myProto 是定义的变量,接受grpc加载的给定路径下的服务,myservices是proto中定义的service
var sum = 0; //定义了一个变量用于计数,客户端每次访问+1,并返回这个计数
const getAsset = (call,callback)=>{ //定义一个getAsset方法
callback(null,{message:(sum++).toString()});
}
const server = new grpc.Server(); //创建一个grpc的服务
server.addProtoService(myProto.assetService.service,{getAsset: getAsset})
//将方法加入到grpc的服务中 //前面一个getAsset指的是上面定义的getAsset方法,后面一个getAsset指的是my.proto中注册的rpc方法
server.bind('127.0.0.1:17041',grpc.ServerCredentials.createInsecure())
//讲服务绑定端口,这里绑定的是本机的17041端口,这个端口可以自行修改
server.start();
//服务启动
如果你现在用命令node myserver.js会报错,这里的报错是因为上面的代码使用了ES6的格式(什么是ES6?),node无法识别,需要使用babel进行转换。安装babel插件的方式为
npm install babel-cli -save-dev
npm install babel-cli -g
npm install babel-preset-es2015 -save-dev
安装完成后,在根目录下新建 .babelrc文件,输入一下代码
{
"presets": [
"es2015"
],
"plugins": []
}
然后在使用 babel-node 文件名去运行
babel-node myserver.js
如果没有error的报错的话,说明服务端已经正常启动。
接下来开始弄客户端,进入到之前创建的 myclient 文件夹里,处理与服务端的js代码不一样,其他的操作都一样,初始化,安装grpc依赖包,编写my.proto文件(这个可以直接从服务端那边拷贝一份过来),安装babel进行转化,唯一不一样的就是客户端的代码
myclient.js如下:
import grpc from 'grpc'
const PROTO_PATH = __dirname+'/asset.proto'
const assetProto = grpc.load(PROTO_PATH).myservices
//前面三步与服务端一样
const client = new assetProto.assetService('127.0.0.1:17041',grpc.credentials.createInsecure());
//这里直接创建一个客户端,端口可以修改
client.getAsset({},(err,res)=>{
console.log('grpc->',res.message);
})
//客户端调用声明在proto文件中的getAsset方法,因为proto文件中声明的传入assetRequest的定义是空白,也就是说不需要传入参数,所以getAsset()的第一个参数是{},getAsset()的第二个参数是个回调函数,这里没有对发生错误的时候进行处理,只是当未发生错误时打印'grpc->'加上服务端的访问次数
ok,客户端的代码也完成了,使用babel-node myclient.js启动客户端。正常情况下会打印次数,客户端每次调用次数都会加1.
写到这里,可能你并没有发现grpc有什么作用,很麻烦,自己写个类似功能(记录访问次数)的客户端和服务端更简单。因为这里只是写一个简单的例子,引导大家入门,你可以想一想,如果服务端进行的操作不是简单的加1.而是访问一个很大的数据库呢,这会消耗很大的cpu和内存,而且如果还有几个另外的会消耗巨大资源的服务端呢?都放在一台电脑上不实际,grpc的作用就是,客户端与服务端可以安装在不同的机器上,只需要修改绑定的ip即可(修改127.0.0.1为其他的ip地址),客户端只需要发送一个请求,不需要其他的资源消耗,而服务端那边会执行你请求的方法,计算完之后返回给你个结果。
rpc在微服务架构中占据很重要的角色,各个容器的相互调用等很多都是依赖于rpc的,而grpc又是rpc中非常有潜力的,所以深入了解一下grpc,百利无一害。