刚接触到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取出回调函数,把运行结果传入回调函数中执行。
9.整个过程完成,详见源码:https://github.com/romulka/nodejs-light_rpc
几个注意的点:
1.整个过程中client和server一直保持连接,不像http协议发送和接收完就断开链接,所以不能以断开链接判断一次数据的传送完成。为了判断数据接收完成,client和server发送的数据遵循一个简单的协议:在数据前加上数据包的长度和分隔符,如定分隔符为\n:[数据包长度\n数据],这样在收到数据后首先取出数据包的长度,再不断判断累计已接收到的数据包是否等于或超过这个长度,若是则一次数据传送完成,可以开始解析提取数据。
2.这个RPC简单在于没有考虑参数里有函数类型的情况,例如有参数是一个object,这个object下有函数成员,JSON序列化时会把函数忽略,在server端是执行不了这个函数的。
为了解决这个问题,需要进行复杂的处理:
1.深度遍历每个要发送给远端的参数,把函数成员抽出来,给这个函数生成唯一id,放到本地一个对象里,把这个函数成员替换成这个id字符串,并标识这个成员实际上是一个函数。这样这个对象就可以序列化发送出去了。
2.server接收到调用,当要使用参数object里的函数时,判断到这是一个经过client处理过的函数,有一个id,把这个id发送回client端,并用同样的方法把自身的回调函数id传给client,等待client端的回调。
3.client端接收到这个函数id,找到这个函数实体,调用,完成后根据server端给的回调id发送回给server端
4.server端收到结果,找到回调函数,继续执行,完成。
函数的记录方法可以以其他方式完成,大体思路就是把函数替换成可序列化的东西,记录函数以便remote端调用时能在本地找到这个函数。可以参考dnode的实现。
Introduction 介绍 Socket and HTTP programming use a message-passing paradigm. A client sends a message to a server which usually sends a message back. Both sides are responsible for creating messages in
问题 你想找到一个简单的方式去执行运行在远程机器上面的Python程序中的函数或方法。 解决方案 实现一个远程方法调用的最简单方式是使用XML-RPC。下面我们演示一下一个实现了键-值存储功能的简单服务器: from xmlrpc.server import SimpleXMLRPCServer class KeyValueServer: _rpc_methods_ = ['get',
说明 此文档只适用于 jboot v3.1.0 以上,之前的版本请参考 这里 。 目录 添加依赖 配置 开始使用 restful 暴露 高级功能 添加依赖 Jboot 支持 dubbo 和 motan,假设我们需要使用 dubbo 作为底层的 RPC 框架,需要添加如下依赖: <dependency> <groupId>org.apache.dubbo</groupId> <art
本文向大家介绍iOS实现远程推送原理及过程,包括了iOS实现远程推送原理及过程的使用技巧和注意事项,需要的朋友参考一下 推送通知,是现在的应用必不可少的功能。那么在 iOS 中,我们是如何实现远程推送的呢?iOS 的远程推送原理又是什么呢?在做 iOS 远程推送时,我们会遇到各种各样的问题。那么首先让我们准备一些做推送需要的东西。我们需要一个付费的苹果开发者账号(免费的不可以做远程推送),有了开发
本文向大家介绍通过 Redis 实现 RPC 远程方法调用(支持多种编程语言),包括了通过 Redis 实现 RPC 远程方法调用(支持多种编程语言)的使用技巧和注意事项,需要的朋友参考一下 我发现经常研究并且为之兴奋的一件事就是对系统进行扩展。现在这对不同的人有着不同的意思。作为移植Monolithic应用到Microservices架构方法中的一部分,如何处理Microservices架构是我
本文向大家介绍说说 RPC 的实现原理相关面试题,主要包含被问及说说 RPC 的实现原理时的应答技巧和注意事项,需要的朋友参考一下 首先需要有处理网络连接通讯的模块,负责连接建立、管理和消息的传输。其次需要有编解码的模块,因为网络通讯都是传输的字节码,需要将我们使用的对象序列化和反序列化。剩下的就是客户端和服务器端的部分,服务器端暴露要开放的服务接口,客户调用服务接口的一个代理实现,这个代理实现负