RPC calls

Similar to Ajax

The first similarity: in short, it is between two devices to call 1. Ajax is browser to server 2. RPC is server to serverCopy the code
The second similarity is that both parties need to agree on a data formatCopy the code

Different from Ajax

1. Ajax uses DNS as the addressing service. 2. 1. Ajax application layer uses HTTP (HTML/JSON) 2. RPC communication generally uses binary protocolCopy the code

Addressing/load balancing

The Ajax addressing process takes the domain name to DNS for resolution, and then initiates the actual requestCopy the code
RPC also requires addressing before making a network request, because IP is not necessarily used for the request, but a uniform identifier such as ID (L5, VIP) may be used, which is parsed by the addressing server, and then the actual request is made through the returned IPCopy the code

TCP communications

Simplex communication: always sending data from one end to the other (client -- server)Copy the code
Half duplex communication: Both parties can send data, but only one end can send data at a time, also known as' round simplex communication 'Copy the code
Full-duplex communication: When the client sends data, the server can also send dataCopy the code

Binary protocol

. Smaller packet size. Faster encoding speed RPC [0001 0000 1111 0101]Copy the code

Node.js Buffer codec binary packets

Introduction to buffer Module

There are three ways to create buffers: Alloc 2. buffer. from 3. buffer. allocUnsafe // From creates a Buffer from an existing data structure const buffer1 = Buffer.from('test'); const buffer2 = Buffer.from([1, 2, 3]); · const buffer3 = buffer. alloc(10); console.log(buffer1); // <Buffer 74 65 73 74> console.log(buffer2); // <Buffer 01 02 03> console.log(buffer3); // <Buffer 00 00 00 00 00 00 00 00 00 00>Copy the code

Buffer.allocUnsafe: This method addresses the memory management mechanism of the Buffer module

Const buffer2 = buffer. from([1, 2, 3]); buffer2.writeInt8(12, 0) console.log(buffer2); // <Buffer 0c 02 03> buffer2.writeInt16BE(512, 1) console.log(buffer2); WriteInt16LE (512, 1) console.log(buffer2); // <Buffer 0c 02 00> BE/LE // <Buffer 0c 00 02> 00 02 // <Buffer 0c 00 02> 00 02 //Copy the code

Protocol buffers library:

Can achieve similar JSON. Stringfly as simple operation, do not need like the one above the trouble to write binary https://github.com/protocolbuffers/protobuf this is compatible with the front end, so there is no above the wellCopy the code
// test.proto

message Test {
  required float num  = 1;
  required string payload = 2;
}
Copy the code
// index.js

const fs = require('fs');
const protobuf = require('protocol-buffers');
const schema = protobuf(fs.readFileSync(__dirname + '/test.proto', 'utf-8'));

console.log(schema)
// Messages {
//   Test: {
//     type: 2,
//     message: true,
//     name: 'Test',
//     buffer: true,
//     encode: [Function: encode] { bytes: 0 },
//     decode: [Function: decode] { bytes: 0 },
//     encodingLength: [Function: encodingLength],
//     dependencies: [ [Object], [Object] ]
//   }
// }
const buffer = schema.Test.encode({
  num: 2,
  payload: 'test'
})
console.log(buffer) // <Buffer 0d 00 00 00 40 12 04 74 65 73 74>
console.log(schema.Test.decode(buffer)) // { num: 2, payload: 'test' }
Copy the code

Node.js net builds multiplexed RPC channels

Net module

Net module is similar to HTTP module, which is relatively simple. Since it is a channel, it has two ends, which are represented by Clinet and ServerCopy the code

Simplex communication case

Half duplex communication case

Full duplex communication

  • server.js
const net = require('net'); const server = net.createServer((socket) => { let oldBuffer = null; Socket. on('data', function (buffer) {if (oldBuffer) {buffer = buffer. concat([oldBuffer, buffer]); } let packageLength = 0; While (packageLength = checkComplete(buffer)) {const package = buffer.slice(0, packageLength); buffer = buffer.slice(packageLength); // unpack this package into data and seq const result = decode(package); Socket. write(encode(LESSON_DATA[result.data], result.seq)); } oldBuffer = buffer; })}); server.listen(4000); Function encode(data, seq) {function encode(data, seq) { Const body = buffer. from(data) const body = buffer. from(data) const body = buffer. from(data) Const header = buffer.alloc (6); const header = buffer.alloc (6); const header = buffer.alloc (6); header.writeInt16BE(seq) header.writeInt32BE(body.length, 2); const buffer = Buffer.concat([header, body]) return buffer; } /** * Binary packet decoding function */ function decode(buffer) {const header = buffer.slice(0, 6); const seq = header.readInt16BE(); // In order not to confuse the point, this example is relatively simple, Const body = buffer.slice(6).readint32be () const body = buffer.slice(6).readint32be () return {seq, data: Body}} /** * Checks if a buffer is a complete packet. * If the buffer is longer than the bodyLength of the header and body, the buffer length is returned, indicating that the buffer is complete. * @param {} buffer */ function checkComplete(buffer) {if (buffer.length < 6) {return 0; } const bodyLength = buffer.readInt32BE(2); Return 6 + bodyLength} / / false data const LESSON_DATA = {136797: "01 | course is an introduction," 136798:02 | content review, 136799: What is "03 | Node. Js"?" 04, 136800: "| Node. Js can be used to do?" 05, 136801: "| course introduces practical project", 136803: "06 | what is technical pre-research?" , 136804: "07 | Node. Js development environment installed", 136806: "08 | the first Node. Js program: rock-paper-scissors game", 136807: "09 | module: CommonJS standard", 136808: "10 | module: using transformation module specification rock-paper-scissors game", 136809:11 | module: NPM, 141994: "12 | module: Node. Js built-in module", 143517: "13 | asynchronous, non-blocking I/O", 143557: "Callback" of 14 | asynchronous: asynchronous programming, 143564: "15 | asynchronous: event loop", 143644: "the Promise of 16 | asynchronous: asynchronous programming", 146470: "17 | asynchronous: the async/await" of asynchronous programming, 146569: "18 | HTTP: HTTP server is what?" 19, 146582: "| HTTP: simple implementation a HTTP server"}Copy the code
  • client.js
const net = require('net'); const socket = new net.Socket({}); Socket.connect ({host: '127.0.0.1', port: 4000}); const LESSON_IDS = [ "136797", "136798", "136799", "136800", "136801", "136803", "136804", "136806", "136807", "136808", "136809", "141994", "143517", "143557", "143564", "143644", "146470", "146569", "146582" ] let id = Math.floor(Math.random() * LESSON_IDS.length); let oldBuffer = null; Socket. on('data', (buffer) => {// Connect the last data event to the residual buffer if (oldBuffer) {buffer = buffer. concat([oldBuffer, buffer]); } let completeLength = 0; While (completeLength = checkComplete(buffer)) {const package = buffer.slice(0, completeLength); buffer = buffer.slice(completeLength); // unpack this package into data and seq const result = decode(package); Console. log(' package ${result.seq}, return value ${result.data} '); } oldBuffer = buffer; }) let seq = 0; Function encode(data) {function encode(data) {function encode(data) { Const body = buffer.alloc (4); const body = buffer.alloc (4); const body = buffer.alloc (4); body.writeInt32BE(LESSON_IDS[data.id]); Const header = buffer.alloc (6); const header = buffer.alloc (6); const header = buffer.alloc (6); header.writeInt16BE(seq) header.writeInt32BE(body.length, 2); // const buffer = buffer.concat ([header, body]) console.log(' package ${seq} is ${LESSON_IDS[data.id]} '); seq++; return buffer; } /** * Binary packet decoding function */ function decode(buffer) {const header = buffer.slice(0, 6); const seq = header.readInt16BE(); Const body = buffer.slice(6) return {seq, data: body.tostring ()}} /** * Checks if a buffer is a complete packet. * If the buffer is longer than the bodyLength of the header and body, the buffer length is returned, indicating that the buffer is complete. * @param {} buffer */ function checkComplete(buffer) {if (buffer.length < 6) {return 0; } const bodyLength = buffer.readInt32BE(2); return 6 + bodyLength } for (let k = 0; k < 100; k++) { id = Math.floor(Math.random() * LESSON_IDS.length); socket.write(encode({ id })); }Copy the code