Baru saja bersentuhan dengan RPC (Remote Procedure Call), yang merupakan metode yang dapat menghubungi program pada mesin jarak jauh secara lokal. Saya melihat implementasi nodeJS sederhana, yang sangat baik untuk mempelajari prinsip RPC: nodeJS light_rpc
Contoh Penggunaan:
Salinan kode adalah sebagai berikut:
// sisi server
var light_rpc = membutuhkan ('./ index.js');
var port = 5556;
var rpc = new light_rpc ({
gabungkan: function (a, b, callback) {
callback (a + b);
},
Multiply: function (t, cb) {
CB (T*2);
}
}). Dengarkan (port);
Contoh klien:
Salinan kode adalah sebagai berikut:
//Klien
rpc.connect (5556, 'localhost', function (remote, conn) {
remote.combine (1, 2, function (res) {
if (res! = 3) {
console.log ('error', res);
}
});
});
Mari kita bicara secara singkat tentang seluruh proses:
1. Sisi server memulai program, mendengarkan port, mengimplementasikan fungsi yang diberikan kepada klien untuk menelepon (seperti menggabungkan dan melipatgandakan dalam contoh di atas), dan menyimpannya dalam suatu objek.
2. Sisi klien memulai program, terhubung ke server, dan mengirimkan perintah menjelaskan setelah koneksi selesai, mengharuskan server untuk mengembalikan nama fungsi yang dapat diberikan untuk dipanggil.
Salinan kode adalah sebagai berikut:
connection.on ('connect', function () {
koneksi.write (perintah (descrcmd));
});
3. Sisi server menerima perintah menjelaskan, membungkus nama fungsi yang dapat dihubungi dan mengirimkannya ("gabungkan", "multiply")
4. Sisi klien menerima nama fungsi yang dikirim oleh server, mendaftarkannya di objeknya sendiri, dan membungkus metode untuk setiap nama fungsi, sehingga ketika fungsi -fungsi ini disebut secara lokal, permintaan sebenarnya dikirim ke sisi server:
Salinan kode adalah sebagai berikut:
untuk (var p di cmd.data) {
RemoteObj [p] = getRemoteCallFunction (p, self.callbacks, koneksi);
// Implementasi GetRemoteCallFunction ditunjukkan di bawah ini
}
5. Sisi klien memanggil fungsi sisi server:
1) Hasilkan ID unik untuk fungsi panggilan balik yang disahkan, yang disebut CallbackID, dan catat dalam objek klien.
2) Kemas data berikut dan kirim ke sisi server: nama fungsi panggilan, daftar parameter serial JSON, callbackid
Salinan kode adalah sebagai berikut:
fungsi getRemoteCallFunction (cmdname, callbacks, connection) {
return function () {
var id = uuid.generate ();
if (typeof argumen [argumen.length-1] == 'function') {
callbacks [id] = argumen [argumen.length-1];
}
var args = parseargumentstoarray.call (ini, argumen);
var newcmd = perintah (cmdname, {id: id, args: args});
Connection.write (newcmd);
}
}
6. Sisi server menerima informasi di atas, mem -parsing data, deserialisasi daftar parameter, dan memanggil fungsi sesuai dengan nama fungsi dan parameter.
Salinan kode adalah sebagai berikut:
var args = cmd.data.args;
args.push (getSendCommandBackFunction (C, cmd.data.id));
self.wrapper [cmd.Command] .Apply ({}, args);
7. Setelah fungsi selesai, serialisasi hasilnya dan kirimkan kembali ke sisi klien bersama dengan ID callbackid yang saya terima sebelumnya.
Salinan kode adalah sebagai berikut:
fungsi getSendCommandBackFunction (koneksi, cmdid) {
return function () {
var innerArgs = parseargumentstoarray.call ({}, argumen);
var resultCommand = perintah (resultCmd, {id: cmdid, args: innerArgs});
Connection.write (hasil hasil);
};
}
8. Sisi klien menerima fungsi menjalankan hasil dan callbackId, mengeluarkan fungsi callback berdasarkan CallbackID, dan meneruskan hasil yang dijalankan ke fungsi callback untuk dieksekusi.
9. Seluruh proses selesai, silakan merujuk ke kode sumber: https://github.com/romulka/nodejs-light_rpc
Beberapa catatan:
1. Klien dan server selalu terhubung sepanjang proses, tidak seperti protokol HTTP yang memutuskan hubungan setelah mengirim dan menerima, sehingga pemutusan tidak dapat digunakan untuk menentukan apakah transmisi data diselesaikan dengan melepaskannya. Untuk menentukan bahwa penerimaan data selesai, data yang dikirim oleh klien dan server mengikuti protokol sederhana: tambahkan panjang paket data dan pemisah sebelum data, seperti pembatas adalah /n: [Panjang paket /data Paket]. Dengan cara ini, setelah menerima data, panjang paket data pertama kali diambil, dan kemudian secara terus -menerus menentukan apakah paket data yang diterima akumulasi sama dengan atau melebihi panjang ini. Jika demikian, transmisi data selesai, dan data dapat diuraikan dan diekstraksi.
2. RPC paling sederhana adalah tidak mempertimbangkan tipe fungsi dalam parameter. Misalnya, jika parameter adalah objek, ada anggota fungsi di bawah objek ini. Saat JSON membuat serial, fungsi akan diabaikan, dan fungsi ini tidak dapat dieksekusi di sisi server.
Untuk mengatasi masalah ini, pemrosesan yang kompleks diperlukan:
1. Dalam melintasi setiap parameter yang akan dikirim ke ujung jarak jauh, mengekstrak anggota fungsi, menghasilkan ID unik untuk fungsi ini, masukkan ke dalam objek lokal, ganti anggota fungsi dengan string ID ini, dan identifikasi bahwa anggota ini sebenarnya adalah fungsi. Dengan cara ini, objek dapat diserialisasi dan dikirim.
2. Ketika server menerima panggilan, ketika ingin menggunakan fungsi pada objek parameter, ia menentukan bahwa ini adalah fungsi yang diproses oleh klien, dengan ID, kirim ID ini kembali ke klien, dan berikan ID fungsi panggilan balik ke klien dengan cara yang sama, menunggu panggilan balik di sisi klien.
3. Sisi klien menerima ID fungsi ini, menemukan entitas fungsi ini, memanggilnya, dan mengirimkannya kembali ke sisi server sesuai dengan ID panggilan balik yang diberikan oleh sisi server.
4. Sisi server menerima hasilnya, menemukan fungsi panggilan balik, terus mengeksekusi, dan menyelesaikannya.
Metode perekaman suatu fungsi dapat diselesaikan dengan cara lain. Gagasan umum adalah untuk mengganti fungsi dengan sesuatu yang dapat serializable, sehingga fungsi dapat ditemukan secara lokal ketika dipanggil di sisi jarak jauh. Anda dapat merujuk pada implementasi DNode.