node.js中RPC(遠(yuǎn)程過(guò)程調(diào)用)的實(shí)現(xiàn)原理介紹
來(lái)源:易賢網(wǎng) 閱讀:983 次 日期:2014-12-19 14:18:24
溫馨提示:易賢網(wǎng)小編為您整理了“node.js中RPC(遠(yuǎn)程過(guò)程調(diào)用)的實(shí)現(xiàn)原理介紹”,方便廣大網(wǎng)友查閱!

使用示例:

代碼如下:

//服務(wù)端

var light_rpc = require('./index.js');

var port = 5556;

var rpc = new light_rpc({

combine: function(a, b, callback){

callback(a + b);

},

multiply: function(t, cb){

cb(t*2);

}

}).listen(port);

Sample client:

代碼如下:

//客戶端

rpc.connect(5556, 'localhost', function(remote, conn){

remote.combine(1, 2, function(res){

if(res != 3){

console.log('ERROR', res);

}

});

});

簡(jiǎn)單說(shuō)說(shuō)整個(gè)過(guò)程:

1.server端啟動(dòng)程序,偵聽(tīng)端口,實(shí)現(xiàn)提供給client調(diào)用的函數(shù)(如上述例子的combine和multiply),保存在一個(gè)對(duì)象里。

2.client端啟動(dòng)程序,連接服務(wù)端,連接完成后發(fā)送describe命令,要求server返回它能提供調(diào)用的函數(shù)名。

代碼如下:

connection.on('connect', function(){

connection.write(command(descrCmd));

});

3.server端接收到describe命令,把自己可供調(diào)用的函數(shù)名包裝好發(fā)送出去(“combine”, “multiply”)

4.client端接收到server發(fā)送的函數(shù)名,注冊(cè)到自己的對(duì)象里,給每個(gè)函數(shù)名包裝一個(gè)方法,使本地調(diào)用這些函數(shù)時(shí)實(shí)際上是向server端發(fā)送請(qǐng)求:

代碼如下:

for(var p in cmd.data){

remoteObj[p] = getRemoteCallFunction(p, self.callbacks, connection);

//getRemoteCallFunction的實(shí)現(xiàn)見(jiàn)下面

}

5.client端調(diào)用server端的函數(shù):

1) 給傳入的callback函數(shù)生成一個(gè)唯一ID,稱為callbackId,記錄到client的一個(gè)對(duì)象里。

2) 包裝好以下數(shù)據(jù)發(fā)送給server端:調(diào)用函數(shù)名,JSON序列化后的參數(shù)列表,callbackId

代碼如下:

function getRemoteCallFunction(cmdName, callbacks, connection){

return function(){

var id = uuid.generate();

if(typeof arguments[arguments.length-1] == 'function'){

callbacks[id] = arguments[arguments.length-1];

}

var args = parseArgumentsToArray.call(this, arguments);

var newCmd = command(cmdName, {id: id, args: args});

connection.write(newCmd);

}

}

6.server端接收到上述信息,解析數(shù)據(jù),對(duì)參數(shù)列表反序列化,根據(jù)函數(shù)名和參數(shù)調(diào)用函數(shù)。

代碼如下:

var args = cmd.data.args;

args.push(getSendCommandBackFunction(c, cmd.data.id));

self.wrapper[cmd.command].apply({}, args);

7.函數(shù)運(yùn)行完成后,把結(jié)果序列化,連同之前收到的callbackId發(fā)送回client端

代碼如下:

function getSendCommandBackFunction(connection, cmdId){

return function(){

var innerArgs = parseArgumentsToArray.call({}, arguments);

var resultCommand = command(resultCmd, {id: cmdId, args: innerArgs});

connection.write(resultCommand);

};

}

8.client端接收到函數(shù)運(yùn)行結(jié)果和callbackId,根據(jù)callbackId取出回調(diào)函數(shù),把運(yùn)行結(jié)果傳入回調(diào)函數(shù)中執(zhí)行。

9.整個(gè)過(guò)程完成,詳見(jiàn)源碼:

幾個(gè)注意的點(diǎn):

1.整個(gè)過(guò)程中client和server一直保持連接,不像http協(xié)議發(fā)送和接收完就斷開(kāi)鏈接,所以不能以斷開(kāi)鏈接判斷一次數(shù)據(jù)的傳送完成。為了判斷數(shù)據(jù)接收完成,client和server發(fā)送的數(shù)據(jù)遵循一個(gè)簡(jiǎn)單的協(xié)議:在數(shù)據(jù)前加上數(shù)據(jù)包的長(zhǎng)度和分隔符,如定分隔符為\n:[數(shù)據(jù)包長(zhǎng)度\n數(shù)據(jù)],這樣在收到數(shù)據(jù)后首先取出數(shù)據(jù)包的長(zhǎng)度,再不斷判斷累計(jì)已接收到的數(shù)據(jù)包是否等于或超過(guò)這個(gè)長(zhǎng)度,若是則一次數(shù)據(jù)傳送完成,可以開(kāi)始解析提取數(shù)據(jù)。

2.這個(gè)RPC簡(jiǎn)單在于沒(méi)有考慮參數(shù)里有函數(shù)類型的情況,例如有參數(shù)是一個(gè)object,這個(gè)object下有函數(shù)成員,JSON序列化時(shí)會(huì)把函數(shù)忽略,在server端是執(zhí)行不了這個(gè)函數(shù)的。

為了解決這個(gè)問(wèn)題,需要進(jìn)行復(fù)雜的處理:

1.深度遍歷每個(gè)要發(fā)送給遠(yuǎn)端的參數(shù),把函數(shù)成員抽出來(lái),給這個(gè)函數(shù)生成唯一id,放到本地一個(gè)對(duì)象里,把這個(gè)函數(shù)成員替換成這個(gè)id字符串,并標(biāo)識(shí)這個(gè)成員實(shí)際上是一個(gè)函數(shù)。這樣這個(gè)對(duì)象就可以序列化發(fā)送出去了。

2.server接收到調(diào)用,當(dāng)要使用參數(shù)object里的函數(shù)時(shí),判斷到這是一個(gè)經(jīng)過(guò)client處理過(guò)的函數(shù),有一個(gè)id,把這個(gè)id發(fā)送回client端,并用同樣的方法把自身的回調(diào)函數(shù)id傳給client,等待client端的回調(diào)。

3.client端接收到這個(gè)函數(shù)id,找到這個(gè)函數(shù)實(shí)體,調(diào)用,完成后根據(jù)server端給的回調(diào)id發(fā)送回給server端

4.server端收到結(jié)果,找到回調(diào)函數(shù),繼續(xù)執(zhí)行,完成。

函數(shù)的記錄方法可以以其他方式完成,大體思路就是把函數(shù)替換成可序列化的東西,記錄函數(shù)以便remote端調(diào)用時(shí)能在本地找到這個(gè)函數(shù)??梢詤⒖糳node的實(shí)現(xiàn)。

更多信息請(qǐng)查看IT技術(shù)專欄

更多信息請(qǐng)查看腳本欄目
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請(qǐng)考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

2026國(guó)考·省考課程試聽(tīng)報(bào)名

  • 報(bào)班類型
  • 姓名
  • 手機(jī)號(hào)
  • 驗(yàn)證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡(jiǎn)要咨詢 | 簡(jiǎn)要咨詢須知 | 新媒體/短視頻平臺(tái) | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號(hào):滇ICP備2023014141號(hào)-1 云南省教育廳備案號(hào):云教ICP備0901021 滇公網(wǎng)安備53010202001879號(hào) 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號(hào)
云南網(wǎng)警備案專用圖標(biāo)
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號(hào):hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報(bào)警專用圖標(biāo)