使用 Node.js 逐步建立多路复用的 RPC 通道
前言
依托 Nodejs 使用 Buffer
net
等模块逐步构建满足应用场景的 RPC 通道
1. RPC 调用
RPC
全称 Remote Procedure Call
翻译成中文:远程过程调用
emm.. 我只是个小前端..
1.1 如何通俗的解释是 RPC?
1.1.1 本地过程调用
1 | 我现在在家里,我需要洗衣服,就把衣服扔到洗衣机洗了 |
1.1.2 远程过程调用 (RPC)
1 | 我现在在逛街,我需要洗衣服,于是给在家里的男票打个哥电话,他把衣服扔到洗衣机洗了 |
1.2 从前端的角度上来理解 RPC 调用?
从我们熟悉的 Ajax 入手,它与 RPC 调用类似,我们来对比一下
1.2.1 相同点
1.2.1.1 都是两个计算机之间的网络通信
- Ajax:客户端和服务端的通信
- PRC:服务器和另外一台服务器的通信
看图说话
1.2.1.2 需要双方约定一个数据格式
1.2.2 不同点
1.2.2.1 不一定使用 DNS 作为寻址服务
- Ajax 是发一个 HTTP 请求,使用 DNS 进行寻址服务
请求过程
- RPC 通信一般是在内网进行请求,使用特有的服务(比如 id)
请求过程
1.2.2.2 应用层协议一般不使用 HTTP
Ajax:使用 HTTP 文本协议(html,json)
RPC: 服务端之间的通信,对效率要求更高所以使用一些二进制协议取代 HTTP,二进制协议性能上存在优势
- 更小的数据包
- 更快的编码速率
1.2.2.3 基于 TCP/UDP 协议
- 浏览器调用(Ajax)使用 TCP 是遵循 HTTP 的规范
- RPC 调用使用了 TCP 多种通信方式
- 单工通信(独木桥)
类比独木桥,两岸同一时间内只能有一方通过
1. 半双工通信(轮番单工通信,独木桥)
1. 全双工通信
2. 使用 Buffter 编解码二进制数据包
用来处理 TCP 链接中的流以及文件系统中的数据
2.1 buffter 创建
1 | const buffter1 = Buffer.from('yishu') |
2.2 buffter 读写
二进制协议:不同字段塞在二进制流中的不同位置
基本操作
1 | buffter2.writeInt8(12,1) |
图示编码二进制包
图解:
前三位代表一个字段,中间代表一个字段,后面又代表一个字段
所以,编码二进制包的时候,我们需要执行三次 write 写操作
看起来还是稍许麻烦嗷
有木有像 Json 格式化方式如此简单的编码方式
答案:有!
使用示例
1 | test.proto |
index.js
1 | const fs = require('fs'); |
明显发现
- 更直观
- 更好维护
- 更便于合作
正是所期盼的这样鸭~
3. 建立多路复用的 RPC 通道
3.1 需求 1 实现单工通信通道
client.js
1 | const net = require('net'); |
server.js
1 | const net = require('net'); |
得到结果
这里实现了 TCP 通信方式之一 单工通信
3.1 需求 2 实现半双工通信通道
3.1.1 客户端和服务器有来有回
- 客户端请求一个正常数据
- 服务端返回一个相应的数据
3.1.2 重点逻辑
在单工通信模式下
- client 端:发请求数据,等到服务器端返回结果之后,再次请求
- server 端:接收到请求后,匹配返回
3.1.3 代码
client.js
1 | const net = require('net'); |
server.js
1 | const net = require('net'); |
3.2 需求 1 实现全双工通信通道
client 端自由发送数据包,无需等待 server 端返回
3.2.1 解决半双工通信的问题
- 半双工通信进行并发容易导致请求包和响应包时序错乱
看图解释一下
- client 同时发送 id1,id2 的请求
- server 端处理…
- server 返回 id2 的处理结果
- server 返回 id1 的处理结果
client 端如何将两个请求和返回数据对应呢?
如果根据返回的时间来进行匹配,就会造成错乱
如何解决?
这正是全双工通信模式要解决的问题
将请求包和返回包都加上一个序号
就像下图这样
3.2.2 重点逻辑
在半双工通信模式下
- client 端:增加 seq,为数据包绑定特有的 id buffer
- server 端:在返回的数据包里绑定 id buffer
3.2.3 代码
client.js
1 |
|
server.js
1 | const net = require('net'); |
得到结果
总结
我们在大量前置知识的基础上,一步步推导出了全双工通道的搭建,当然了,这是不完整的,还有一些情况需要处理
回顾一下全双工通道搭建过程
- 关键在于应用层协议需要有标记包号的字段✅
- 处理以下情况,需要有标记包长的字段
- 出现原因:TCP 底层优化机制,把同时发的一些包拼起来
- 粘包❎
- 不完整包❎
- 错误处理
- 网络等
希望读完本文,你会对 RPC 通道有些粗浅的认识
未完待续..