什么是 RPC
本篇是极客时间杨浩老师的概括总结。首先点开这篇文章的你肯定会疑惑,什么是RPC呢?既然有了HTTP协议为什么还需要RPC?
RPC 与 HTTP 作比较
- RPC本质上不算是协议,而是一种调用方式
- RPC的实现是基于Socket之上的
- HTTP是90年代才开始流行的,在TCP之上之前有很多替代的协议,这就包括RPC,也就说在没有HTTP协议的时代,很多人用RPC发送数据的。
那为什么现在有了 HTTP 我们还需要学习 RPC 呢?
有一个比较直观的理解就是在 c/s 架构下 (client/server), RPC 可以使用在公司内网,进行数据传输。
RPC 的技术不同点
- 不一定使用DNS作为寻址服务(在内网里互相请求)
- RPC应用层协议通常不使用HTTP,而是采用基于二进制的协议来替代HTTP
RPC传输二进制协议,相比HTTP
更小的数据包体积
更快的编解码速率
- 基于TCP或UDP协议
RPC 技术实现
二进制传输实现
使用 Node.js 中的 Buffer API 详情见官网文档Buffer | Node.js v18.17.1 Documentation (nodejs.org)
这里需要掌握两个创建 Buffer 的语法,用于二进制传输
Buffer.from
- 可以接受多种输入类型作为参数,包括字符串、数组、Buffer对象
- 提供的数据可以直接填充到Buffer中,
const bufferFromStr = Buffer.from('Hello');
- 如果提供了字符串,则可以指定编码格式,例如'utf8'、'hex'等,默认为'utf8'。
Buffer.alloc
- 创建指定大小的新的Buffer对象,并将所有字节设置为零(初始化)。
- 接受一个整数参数,表示要分配的字节数。
RPC 半双工代码
server 端
js
const net = require('net')
const server = net.createServer((socket) => {
socket.on('data', function (buffer) {
const fruitId = buffer.readInt32BE()
const fruitData = data[fruitId];
if(fruitData !== undefined) {
const bufferc = Buffer.from(fruitData);
setTimeout(() => {
socket.write(bufferc);
}, 500);
} else {
console.log("fruitId: " + fruitId + " doesn't exist.")
}
console.log(buffer, buffer.toString())
})
})
const data = {
136797: "01 草莓",
136798:"02 香蕉",
136799: "03 西瓜",
136808: "04 榴莲",
136801: "05 菠萝蜜",
136803: "06 香瓜",
136804: "07 白兰瓜",
}
server.listen(4000)
client 端
js
const net = require('net')
const socket = new net.Socket({})
socket.connect({
host: '127.0.0.1',
port: 4000
})
const id = [
"136797",
"136798",
"136799",
"136808",
"136801",
"136803",
"136804",
]
// 请求第一次发送
let index = Math.floor(Math.random() * id.length)
socket.write(encode(index))
socket.on('data', (buffer) => {
const fruitBuffer = buffer;
console.log(fruitBuffer.toString())
index = Math.floor(Math.random() * id.length)
socket.write(encode(index))
})
function encode(index) {
let buffer = Buffer.alloc(4)
buffer.writeInt32BE(
id[index]
)
console.log(id[index])
return buffer
}