[node.js]RPC(遠端程序呼叫)的實現原理

來源:互聯網
上載者:User

剛接觸到RPC(遠端程序呼叫),就是可以在本地調用遠程機子上的程式的方法,看到一個簡單的nodejs實現,用來學習RPC的原理很不錯:nodejs light_rpc 使用樣本: //服務端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);        }    });});   簡單說說整個過程: 1.server端啟動程式,偵聽連接埠,實現提供給client調用的函數(如上述例子的combine和multiply),儲存在一個對象裡。 2.client端啟動程式,串連服務端,串連完成後發送describe命令,要求server返回它能提供調用的函數名。 connection.on('connect', function(){  connection.write(command(descrCmd));});3.server端接收到describe命令,把自己可供調用的函數名封裝好發送出去(“combine”, “multiply”) 4.client端接收到server發送的函數名,註冊到自己的對象裡,給每個函數名封裝一個方法,使本地調用這些函數時實際上是向server端發送請求: for(var p in cmd.data){  remoteObj[p] = getRemoteCallFunction(p, self.callbacks, connection);  //getRemoteCallFunction的實現見下面}5.client端調用server端的函數: 1) 給傳入的callback函數產生一個唯一ID,稱為callbackId,記錄到client的一個對象裡。 2) 封裝好以下資料發送給server端:調用函數名,JSON序列化後的參數列表,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端接收到上述資訊,解析資料,對參數列表還原序列化,根據函數名和參數調用函數。 var args = cmd.data.args;args.push(getSendCommandBackFunction(c, cmd.data.id));self.wrapper[cmd.command].apply({}, args);7.函數運行完成後,把結果序列化,連同之前收到的callbackId發送回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端接收到函數運行結果和callbackId,根據callbackId取出回呼函數,把運行結果傳入回呼函數中執行。 self.callbacks[cmd.data.id].apply(this, cmd.data.args);9.整個過程完成,詳見源碼:https://github.com/romulka/nodejs-light_rpc   幾個注意的點: 1.整個過程中client和server一直保持串連,不像http協議發送和接收完就取消連結,所以不能以取消連結判斷一次資料的傳送完成。為了判斷資料接收完成,client和server發送的資料遵循一個簡單的協議:在資料前加上資料包的長度和分隔字元,如定分隔字元為\n:[資料包長度\n資料],這樣在收到資料後首先取出資料包的長度,再不斷判斷累計已接收到的資料包是否等於或超過這個長度,若是則一次資料傳送完成,可以開始解析提取資料。 2.這個RPC簡單在於沒有考慮參數裡有函數類型的情況,例如有參數是一個object,這個object下有函數成員,JSON序列化時會把函數忽略,在server端是執行不了這個函數的。 為瞭解決這個問題,需要進行複雜的處理: 深度遍曆每個要發送給遠端的參數,把函數成員抽出來,給這個函數產生唯一id,放到本地一個對象裡,把這個函數成員替換成這個id字串,並標識這個成員實際上是一個函數。這樣這個對象就可以序列化發送出去了。server接收到調用,當要使用參數object裡的函數時,判斷到這是一個經過client處理過的函數,有一個id,把這個id發送回client端,並用同樣的方法把自身的回呼函數id傳給client,等待client端的回調。client端接收到這個函數id,找到這個函數實體,調用,完成後根據server端給的回調id發送回給server端server端收到結果,找到回呼函數,繼續執行,完成。函數的記錄方法可以以其他方式完成,大體思路就是把函數替換成可序列化的東西,記錄函數以便remote端調用時能在本地找到這個函數。可以參考dnode的實現。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.