Acabei de entrar em contato com o RPC (chamada de procedimento remoto), que é um método que pode chamar programas em máquinas remotas localmente. Vi uma implementação simples de NodeJS, que é muito boa para aprender o princípio do RPC: Nodejs Light_RPC
Exemplo de uso:
A cópia do código é a seguinte:
// lado do servidor
var luz_rpc = requer ('./ index.js');
VAR porta = 5556;
var rpc = new Light_rpc ({
Combine: function (a, b, retorno de chamada) {
retorno de chamada (a + b);
},
Multiply: function (t, cb) {
CB (T*2);
}
}). Ouça (porta);
Cliente de amostra:
A cópia do código é a seguinte:
//Cliente
rpc.connect (5556, 'localhost', função (remoto, conn) {
remote.combine (1, 2, função (res) {
if (res! = 3) {
console.log ('erro', res);
}
});
});
Vamos falar brevemente sobre todo o processo:
1. O lado do servidor inicia o programa, ouve a porta, implementa as funções fornecidas ao cliente para ligar (como combinar e multiplicar no exemplo acima) e salva -as em um objeto.
2. O lado do cliente inicia o programa, se conecta ao servidor e envia um comando descrever após a conclusão da conexão, exigindo que o servidor retorne o nome da função que ele pode fornecer para ligar.
A cópia do código é a seguinte:
Connection.on ('Connect', function () {
Connection.Write (Command (Descrcmd));
});
3. O lado do servidor recebe o comando descrever, envolve o nome da função que pode chamar e envia ("Combine", "Multiply")
4. O lado do cliente recebe o nome da função enviado pelo servidor, registra -o em seu próprio objeto e envolve um método para cada nome de função, para que, quando essas funções sejam chamadas localmente, uma solicitação é realmente enviada para o lado do servidor:
A cópia do código é a seguinte:
para (var p em cmd.data) {
RemoteObj [p] = getRemoteCallFunction (p, self.callbacks, conexão);
// A implementação do getRemoteCallFunction é mostrada abaixo
}
5. O lado do cliente chama as funções do lado do servidor:
1) Gere um ID exclusivo para a função de retorno de chamada passada, chamado chamada de chamada e grave -o em um objeto do cliente.
2) Empaco
A cópia do código é a seguinte:
função getRemoteCallfunction (cmdname, retornos de chamada, conexão) {
Return function () {
var id = uuid.GeReRe ();
if (typeof argumentos [argumentos.Length-1] == 'function') {
retornos de chamada [id] = argumentos [argumentos.Length-1];
}
var args = parseargumentstoarray.call (this, argumentos);
var newcmd = comando (cmdname, {id: id, args: args});
Connection.Write (newcmd);
}
}
6. O lado do servidor recebe as informações acima, analisa os dados, desaperializa a lista de parâmetros e chama a função de acordo com o nome da função e os parâmetros.
A cópia do código é a seguinte:
var args = cmd.data.args;
args.push (getSendCommandBackFunction (c, cmd.data.id));
Self.wrapper [cmd.command] .Apply ({}, args);
7. Após a conclusão da função, serialize o resultado e envie -a de volta ao lado do cliente, juntamente com o ID de chamada que recebi antes.
A cópia do código é a seguinte:
função getSendCommandBackFunction (conexão, cmdid) {
Return function () {
var inerargs = parseargumentstoarray.call ({}, argumentos);
var resultCommand = command (resultadocmd, {id: cmdid, args: inerArgs});
Connection.Write (resultadoCommand);
};
}
8. O lado do cliente recebe o resultado em execução da função e o retorno de chamada, retira a função de retorno de chamada com base no chamado e passa o resultado da execução na função de retorno de chamada para execução.
9. Todo o processo é concluído, consulte o código-fonte: https://github.com/romulka/nodejs-light_rpc
Algumas notas:
1. O cliente e o servidor estão sempre conectados ao longo do processo, diferentemente do protocolo HTTP que desconecta o link após o envio e o recebimento, para que a desconexão não possa ser usada para determinar se a transmissão de dados é concluída desconectando -o. Para determinar que a recepção de dados é concluída, os dados enviados pelo cliente e o servidor seguem um protocolo simples: adicione o comprimento do pacote de dados e o separador antes dos dados, como o delimitador IS /N: [Comprimento do pacote /N dados]. Dessa forma, após o recebimento dos dados, o comprimento do pacote de dados é recuperado pela primeira vez e, em seguida, determina continuamente se os pacotes de dados recebidos acumulados são iguais ou excedem esse comprimento. Nesse caso, a transmissão de dados é concluída e os dados podem ser analisados e extraídos.
2. O RPC mais simples é que ele não considera o tipo de função no parâmetro. Por exemplo, se um parâmetro for um objeto, existem membros da função nesse objeto. Quando JSON serializa, a função será ignorada e essa função não pode ser executada no lado do servidor.
Para resolver esse problema, é necessário um processamento complexo:
1. Atravesse profundamente cada parâmetro a ser enviado para a extremidade remota, extrair o membro da função, gerar um ID exclusivo para esta função, coloque -o em um objeto local, substitua o membro da função por essa sequência de ID e identifique que esse membro é realmente uma função. Dessa maneira, o objeto pode ser serializado e enviado.
2. Quando o servidor recebe uma chamada, quando deseja usar a função no objeto do parâmetro, ele determina que essa é uma função processada pelo cliente, com um ID, envie esse ID de volta ao cliente e passe o ID da função de retorno de chamada para o cliente da mesma maneira, aguardando o retorno do lado do cliente.
3. O lado do cliente recebe esse ID da função, encontra essa entidade de função, chama e o envia de volta ao lado do servidor de acordo com o ID de retorno de chamada fornecido pelo lado do servidor.
4. O lado do servidor recebe o resultado, encontra a função de retorno de chamada, continua a executar e conclui.
O método de gravação de uma função pode ser concluído de outras maneiras. A idéia geral é substituir a função por algo serializável, para que a função possa ser encontrada localmente quando chamado no lado remoto. Você pode consultar a implementação do DNODE.