เพิ่งเข้ามาติดต่อกับ RPC (การโทรขั้นตอนระยะไกล) ซึ่งเป็นวิธีที่สามารถโทรโปรแกรมบนเครื่องรีโมตในพื้นที่ได้ ฉันเห็นการใช้งาน NodeJS อย่างง่ายซึ่งเป็นสิ่งที่ดีมากสำหรับการเรียนรู้หลักการของ RPC: NodeJS LIGHT_RPC
ตัวอย่างการใช้งาน:
การคัดลอกรหัสมีดังนี้:
// ฝั่งเซิร์ฟเวอร์
var light_rpc = ต้องการ ('./ index.js');
พอร์ต var = 5556;
var rpc = new light_rpc ({
รวม: ฟังก์ชั่น (a, b, โทรกลับ) {
การโทรกลับ (a + b);
-
ทวีคูณ: ฟังก์ชั่น (t, cb) {
CB (t*2);
-
}). ฟัง (พอร์ต);
ตัวอย่างไคลเอนต์:
การคัดลอกรหัสมีดังนี้:
//ลูกค้า
rpc.connect (5556, 'localhost', ฟังก์ชั่น (ระยะไกล, conn) {
remote.combine (1, 2, ฟังก์ชั่น (res) {
ถ้า (res! = 3) {
console.log ('ข้อผิดพลาด', res);
-
-
-
พูดคุยสั้น ๆ เกี่ยวกับกระบวนการทั้งหมด:
1. ฝั่งเซิร์ฟเวอร์เริ่มโปรแกรมฟังพอร์ตใช้ฟังก์ชั่นที่ให้กับไคลเอนต์เพื่อโทร (เช่นรวมและคูณในตัวอย่างข้างต้น) และบันทึกไว้ในวัตถุ
2. ฝั่งไคลเอ็นต์เริ่มโปรแกรมเชื่อมต่อกับเซิร์ฟเวอร์และส่งคำสั่งอธิบายหลังจากการเชื่อมต่อเสร็จสมบูรณ์โดยกำหนดให้เซิร์ฟเวอร์กลับชื่อฟังก์ชั่นที่สามารถให้โทรได้
การคัดลอกรหัสมีดังนี้:
Connection.on ('Connect', function () {
Connection.write (คำสั่ง (descrcmd));
-
3. ฝั่งเซิร์ฟเวอร์ได้รับคำสั่งอธิบาย, ห่อชื่อฟังก์ชั่นที่สามารถโทรและส่งออก ("รวม", "ทวีคูณ")
4. ฝั่งไคลเอ็นต์ได้รับชื่อฟังก์ชั่นที่ส่งโดยเซิร์ฟเวอร์ลงทะเบียนในวัตถุของตัวเองและห่อเมธอดสำหรับแต่ละชื่อฟังก์ชันดังนั้นเมื่อฟังก์ชั่นเหล่านี้เรียกว่าในเครื่องจะส่งคำขอไปยังฝั่งเซิร์ฟเวอร์จริง ๆ :
การคัดลอกรหัสมีดังนี้:
สำหรับ (var p ใน cmd.data) {
remoteobj [p] = getRemoteCallFunction (p, self.callbacks, การเชื่อมต่อ);
// การใช้งาน getRemotecallFunction แสดงอยู่ด้านล่าง
-
5. ฝั่งไคลเอ็นต์เรียกฟังก์ชั่นด้านเซิร์ฟเวอร์:
1) สร้าง ID ที่ไม่ซ้ำกันสำหรับฟังก์ชั่นการโทรกลับที่ผ่านมาเรียกว่า callbackid และบันทึกไว้ในวัตถุของไคลเอนต์
2) แพ็คข้อมูลต่อไปนี้และส่งไปยังฝั่งเซิร์ฟเวอร์: ชื่อฟังก์ชันการโทร, รายการพารามิเตอร์ Serialized JSON, callbackId
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น getRemoteCallFunction (cmdname, callbacks, การเชื่อมต่อ) {
return function () {
var id = uuid.generate ();
if (typeof arguments [arguments.length-1] == 'function') {
การโทรกลับ [id] = อาร์กิวเมนต์ [arguments.length-1];
-
var args = parseargumentstoarray.call (นี่, อาร์กิวเมนต์);
var newcmd = คำสั่ง (cmdname, {id: id, args: args});
Connection.write (newcmd);
-
-
6. ฝั่งเซิร์ฟเวอร์ได้รับข้อมูลข้างต้นแยกวิเคราะห์ข้อมูล deserializes รายการพารามิเตอร์และเรียกใช้ฟังก์ชันตามชื่อฟังก์ชันและพารามิเตอร์
การคัดลอกรหัสมีดังนี้:
var args = cmd.data.args;
args.push (getSendCommandBackfunction (C, cmd.data.id));
self.wrapper [cmd.command] .apply ({}, args);
7. หลังจากฟังก์ชั่นเสร็จสมบูรณ์ให้เป็นอนุกรมผลลัพธ์และส่งกลับไปยังฝั่งไคลเอ็นต์พร้อมกับ ID callbackid ที่ฉันได้รับมาก่อน
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น getSendCommandBackFunction (การเชื่อมต่อ, cmdid) {
return function () {
var innerargs = parseargumentStoarray.call ({}, อาร์กิวเมนต์);
var resultCommand = คำสั่ง (resultcmd, {id: cmdid, args: innerargs});
Connection.write (resultCommand);
-
-
8. ฝั่งไคลเอ็นต์ได้รับฟังก์ชั่นการทำงานและการเรียกกลับใช้ฟังก์ชันการโทรกลับตามการเรียกกลับและส่งผลการเรียกใช้ในฟังก์ชั่นการเรียกกลับเพื่อดำเนินการ
9. กระบวนการทั้งหมดเสร็จสมบูรณ์โปรดดูที่ซอร์สโค้ด: https://github.com/romulka/nodejs-light_rpc
หมายเหตุเล็กน้อย:
1. ไคลเอนต์และเซิร์ฟเวอร์เชื่อมต่ออยู่เสมอตลอดกระบวนการซึ่งแตกต่างจากโปรโตคอล HTTP ที่ตัดการเชื่อมต่อลิงค์หลังจากส่งและรับดังนั้นการตัดการเชื่อมต่อจึงไม่สามารถใช้เพื่อตรวจสอบว่าการส่งข้อมูลเสร็จสมบูรณ์โดยการตัดการเชื่อมต่อหรือไม่ เพื่อตรวจสอบว่าการรับข้อมูลเสร็จสมบูรณ์ข้อมูลที่ส่งโดยไคลเอนต์และเซิร์ฟเวอร์ทำตามโปรโตคอลอย่างง่าย: เพิ่มความยาวของแพ็กเก็ตข้อมูลและตัวคั่นก่อนที่ข้อมูลเช่นตัวคั่น IS /N: [ข้อมูลความยาวแพ็คเก็ต /N] ด้วยวิธีนี้หลังจากได้รับข้อมูลความยาวของแพ็กเก็ตข้อมูลจะถูกเรียกคืนก่อนแล้วจึงตรวจสอบอย่างต่อเนื่องว่าแพ็กเก็ตข้อมูลที่ได้รับจะเท่ากับหรือสูงกว่าความยาวนี้หรือไม่ ถ้าเป็นเช่นนั้นการส่งข้อมูลจะเสร็จสมบูรณ์และข้อมูลสามารถแยกวิเคราะห์และสกัดได้
2. RPC ที่ง่ายที่สุดคือไม่พิจารณาประเภทฟังก์ชันในพารามิเตอร์ ตัวอย่างเช่นหากพารามิเตอร์เป็นวัตถุมีสมาชิกฟังก์ชั่นภายใต้วัตถุนี้ เมื่อ JSON serializes ฟังก์ชั่นจะถูกละเว้นและฟังก์ชั่นนี้ไม่สามารถดำเนินการทางฝั่งเซิร์ฟเวอร์ได้
เพื่อแก้ปัญหานี้จำเป็นต้องมีการประมวลผลที่ซับซ้อน:
1. สำรวจแต่ละพารามิเตอร์ที่จะส่งไปยังปลายระยะไกลแยกสมาชิกฟังก์ชั่นสร้าง ID ที่ไม่ซ้ำกันสำหรับฟังก์ชั่นนี้ใส่ไว้ในวัตถุท้องถิ่นแทนที่สมาชิกฟังก์ชั่นด้วยสตริง ID นี้และระบุว่าสมาชิกนี้เป็นฟังก์ชั่นจริง ด้วยวิธีนี้วัตถุสามารถทำให้เป็นอนุกรมและส่งออก
2. เมื่อเซิร์ฟเวอร์ได้รับการโทรเมื่อต้องการใช้ฟังก์ชั่นในวัตถุพารามิเตอร์จะกำหนดว่านี่เป็นฟังก์ชั่นที่ดำเนินการโดยไคลเอนต์ด้วย ID ส่ง ID นี้กลับไปยังไคลเอนต์และส่งรหัสฟังก์ชันการโทรกลับไปยังไคลเอนต์ในลักษณะเดียวกันรอการโทรกลับทางฝั่งไคลเอ็นต์
3. ฝั่งไคลเอ็นต์ได้รับ ID ฟังก์ชั่นนี้พบเอนทิตีฟังก์ชั่นนี้โทรและส่งกลับไปยังฝั่งเซิร์ฟเวอร์ตามรหัสการโทรกลับที่กำหนดโดยฝั่งเซิร์ฟเวอร์
4. ฝั่งเซิร์ฟเวอร์ได้รับผลลัพธ์ค้นหาฟังก์ชั่นการโทรกลับยังคงดำเนินการและดำเนินการให้เสร็จสมบูรณ์
วิธีการบันทึกของฟังก์ชั่นสามารถทำได้ในวิธีอื่น แนวคิดทั่วไปคือการแทนที่ฟังก์ชั่นด้วยสิ่งที่ทำให้เป็นอนุกรมเพื่อให้สามารถพบฟังก์ชั่นในพื้นที่เมื่อถูกเรียกทางด้านรีโมต คุณสามารถอ้างถึงการใช้งาน DNODE