Acabo de entrar en contacto con RPC (llamada de procedimiento remoto), que es un método que puede llamar a programas en máquinas remotas localmente. Vi una implementación simple de NodeJS, que es muy buena para aprender el principio de RPC: NodeJS Light_RPC
Ejemplo de uso:
La copia del código es la siguiente:
// lado del servidor
var light_rpc = require ('./ index.js');
puerto var = 5556;
var rpc = new Light_rpc ({
Combinar: función (a, b, devolución de llamada) {
devolución de llamada (a + b);
},
multiplicar: function (t, cb) {
CB (t*2);
}
}). Escuchar (puerto);
Muestra de cliente:
La copia del código es la siguiente:
//Cliente
rpc.connect (5556, 'localhost', function (remoto, conn) {
remoto.combine (1, 2, function (res) {
if (res! = 3) {
console.log ('error', res);
}
});
});
Hablemos brevemente sobre todo el proceso:
1. El lado del servidor inicia el programa, escucha el puerto, implementa las funciones proporcionadas al cliente para llamar (como combinar y multiplicar en el ejemplo anterior) y las guarda en un objeto.
2. El lado del cliente inicia el programa, se conecta al servidor y envía un comando Describe después de que se complete la conexión, lo que requiere que el servidor devuelva el nombre de la función que puede proporcionar a la llamada.
La copia del código es la siguiente:
Connection.On ('Connect', function () {
Connection.Write (comando (descrCmd));
});
3. El lado del servidor recibe el comando Describe, envuelve el nombre de la función que puede llamar y lo envía ("Combinar", "multiplicar")
4. El lado del cliente recibe el nombre de la función enviado por el servidor, lo registra en su propio objeto y envuelve un método para cada nombre de la función, de modo que cuando estas funciones se denominan localmente, una solicitud realmente se envía al lado del servidor:
La copia del código es la siguiente:
para (var p en cmd.data) {
remotosbj [p] = getRemotecallFunction (p, self.callbacks, conexión);
// La implementación de GetRemotecallFunction se muestra a continuación
}
5. El lado del cliente llama a las funciones del lado del servidor:
1) Genere una ID única para la función de devolución de llamada pasada, llamada CallbackId, y registela en un objeto del cliente.
2) Empaque los siguientes datos y envíelo al lado del servidor: Nombre de la función de llamada, Lista de parámetros serializados JSON, Callbackid
La copia del código es la siguiente:
function getRemotecallFunction (cmdname, callbacks, conexión) {
Función de retorno () {
var id = uuid.generate ();
if (typeof argumentos [argumentos.length-1] == 'function') {
Callbacks [id] = argumentos [argumentos.length-1];
}
var args = parseargumentstoarray.call (this, argumentos);
var newCmd = command (cmdName, {id: id, args: args});
Connection.Write (NewCMD);
}
}
6. El lado del servidor recibe la información anterior, analiza los datos, deserializa la lista de parámetros y llama a la función de acuerdo con el nombre de la función y los parámetros.
La copia del código es la siguiente:
var args = cmd.data.args;
args.push (getSendCommandbackFunction (c, cmd.data.id));
self.wrapper [cmd.command] .apply ({}, args);
7. Después de completar la función, sea serialice el resultado y envíelo de regreso al lado del cliente junto con la identificación de devolución de llamada que recibí antes.
La copia del código es la siguiente:
función getSendCommandBackFunction (Connection, CMDID) {
Función de retorno () {
var intargs = parseargumentStoarray.call ({}, argumentos);
var resultCommand = command (resultCmd, {id: cmdid, args: innerargs});
Connection.Write (resultCommand);
};
}
8. El lado del cliente recibe la función que ejecuta el resultado y la devoción de llamada, elimina la función de devolución de llamada en función de CallbackId y pasa el resultado de ejecución en la función de devolución de llamada para la ejecución.
9. Todo el proceso se completa, consulte el código fuente: https://github.com/romulka/nodejs-light_rpc
Algunas notas:
1. El cliente y el servidor siempre están conectados durante todo el proceso, a diferencia del protocolo HTTP que desconecta el enlace después de enviar y recibir, por lo que la desconexión no puede usarse para determinar si la transmisión de datos se completa al desconectarlo. Para determinar que la recepción de datos se completa, los datos enviados por el cliente y el servidor siguen un protocolo simple: agregue la longitud del paquete de datos y el separador antes de los datos, como el delimitador es /N: [Longitud del paquete /n Datos]. De esta manera, después de recibir los datos, la longitud del paquete de datos se recupera primero y luego determina continuamente si los paquetes de datos recibidos acumulados son iguales o exceden esta longitud. Si es así, la transmisión de datos se completa y los datos se pueden analizar y extraer.
2. El RPC más simple es que no considera el tipo de función en el parámetro. Por ejemplo, si un parámetro es un objeto, hay miembros de la función en este objeto. Cuando JSON es serie, la función se ignorará y esta función no se puede ejecutar en el lado del servidor.
Para resolver este problema, se requiere un procesamiento complejo:
1. Atraviese profundamente cada parámetro que se enviará al extremo remoto, extrae el miembro de la función, genere una ID única para esta función, coloque en un objeto local, reemplace el miembro de la función con esta cadena de identificación e identifique que este miembro es realmente una función. De esta manera, el objeto se puede serializar y enviar.
2. Cuando el servidor recibe una llamada, cuando desea usar la función en el objeto de parámetro, determina que esta es una función procesada por el cliente, con una ID, envíe esta ID al cliente y pase la ID de función de devolución de llamada al cliente de la misma manera, esperando la devolución de llamada en el lado del cliente.
3. El lado del cliente recibe esta ID de función, encuentra esta entidad de función, la llama y la envía nuevamente al lado del servidor de acuerdo con la ID de devolución de llamada dada por el lado del servidor.
4. El lado del servidor recibe el resultado, encuentra la función de devolución de llamada, continúa ejecutándose y se completa.
El método de grabación de una función se puede completar de otras maneras. La idea general es reemplazar la función con algo serializable, para que la función se pueda encontrar localmente cuando se le solicite en el lado remoto. Puede consultar la implementación de DNODE.