Только что вступил в контакт с RPC (удаленный вызов процедуры), который является методом, который может вызовать программы на удаленных машинах локально. Я видел простую реализацию Nodejs, которая очень хороша для изучения принципа RPC: Nodejs Light_RPC
Пример использования:
Кода -копия выглядит следующим образом:
// Серверная сторона
var light_rpc = require ('./ index.js');
var port = 5556;
var rpc = new Light_rpc ({
Комбинировать: function (a, b, обратный вызов) {
обратный вызов (a + b);
},
умножить: function (t, cb) {
CB (T*2);
}
}). Слушайте (порт);
Образец клиента:
Кода -копия выглядит следующим образом:
// клиент
rpc.connect (5556, 'localhost', function (remote, conn) {
remote.combine (1, 2, function (res) {
if (res! = 3) {
console.log ('error', res);
}
});
});
Давайте кратко поговорим обо всем процессе:
1. На стороне сервера запускает программа, слушает порт, реализует функции, предоставленные клиенту для вызова (например, объединение и умножение в приведенном выше примере), и сохраняет их в объекте.
2. Сторона клиента запускает программу, подключается к серверу и отправляет команду Description после завершения подключения, требуя от сервера возвращать имя функции, которое он может предоставить вызову.
Кода -копия выглядит следующим образом:
connection.on ('connect', function () {
connection.write (command (desccmd));
});
3. Сторона сервера получает команду Description, завершает имя функции, которое она может вызвать, и отправляет ее («Объединить», «Умножение»)
4. Сторона клиента получает имя функции, отправленное сервером, регистрирует его в своем собственном объекте и завершает метод для каждого имени функции, так что, когда эти функции называются локально, запрос фактически отправляется на сторону сервера:
Кода -копия выглядит следующим образом:
для (var p в cmd.data) {
remoteObj [p] = getRemotecallFunction (p, self.callbacks, connection);
// реализация getRemoteCallFunction показана ниже
}
5. Клиентская сторона вызывает функции на стороне сервера:
1) Сгенерировать уникальный идентификатор для выполненной функции обратного вызова, называемого CallbackID, и запишите его в объекте клиента.
2) Упакуйте следующие данные и отправьте его на сторону сервера: имя функции вызова, Список параметров JSON, CallbackId
Кода -копия выглядит следующим образом:
функция getRemoteCallFunction (cmdName, обратные вызовы, соединение) {
return function () {
var id = uuid.generate ();
if (typeof Arguments [Arguments.length-1] == 'function') {
обратные вызовы [id] = аргументы [arguments.length-1];
}
var args = pacergumentstoarray.call (это, аргументы);
var newCmd = command (cmdName, {id: id, args: args});
connection.write (newcmd);
}
}
6. Сторона сервера получает приведенную выше информацию, анализирует данные, десериализует список параметров и вызывает функцию в соответствии с именем функции и параметрами.
Кода -копия выглядит следующим образом:
var args = cmd.data.args;
args.push (getsendcommandbackfunction (c, cmd.data.id));
self.wrapper [cmd.command] .apply ({}, args);
7. После завершения функции сериализуйте результат и отправьте его обратно на сторону клиента вместе с идентификатором CallbackID, который я получил ранее.
Кода -копия выглядит следующим образом:
Функция getSendCommandbackfunction (Connection, cmdid) {
return function () {
var innerargs = pacergumentstoarray.call ({}, аргументы);
var rescodcommand = command (resultCmd, {id: cmdid, args: innerargs});
connection.write (rescentCommand);
};
}
8. Сторона клиента получает функцию, использующую результат и CallbackID, снимает функцию обратного вызова на основе CallbackID и передает результат выполнения в функцию обратного вызова для выполнения.
9. Весь процесс завершен, обратитесь к исходному коду: https://github.com/romulka/nodejs-light_rpc
Несколько заметок:
1. Клиент и сервер всегда подключены на протяжении всего процесса, в отличие от протокола HTTP, который отключает ссылку после отправки и получения, поэтому отключение не может быть использовано для определения того, завершена ли передача данных путем отключения. Чтобы определить, что прием данных завершен, данные, отправленные клиентом и сервером, следуют простую протоколу: добавьте длину пакета данных и сепаратор перед данными, такими как разделитель IS /N: [Длина пакета /N]. Таким образом, после получения данных длина пакета данных сначала получена, а затем постоянно определяет, равны ли накопленные пакеты полученных данных или превышают эту длину. Если это так, передача данных завершена, и данные могут быть проанализированы и извлечены.
2. Самый простой RPC заключается в том, что он не учитывает тип функции в параметре. Например, если параметр является объектом, в этом объекте есть элементы функций. Когда JSON сериализуется, функция будет проигнорирована, и эта функция не может быть выполнена на стороне сервера.
Чтобы решить эту проблему, требуется сложная обработка:
1. Глубоко пройти каждый параметр, который будет отправлен на удаленный конец, извлеките функциональный элемент, генерируйте уникальный идентификатор для этой функции, поместите его в локальный объект, замените элемент функции на эту идентификационную строку и определите, что этот элемент на самом деле является функцией. Таким образом, объект может быть сериализован и отправлен.
2. Когда сервер получает вызов, когда он хочет использовать функцию в объекте параметра, он определяет, что это функция, обрабатываемая клиентом, с идентификатором, отправьте этот идентификатор обратно клиенту и передайте идентификатор функции обратного вызова клиенту таким же образом, ожидая обратного вызова на стороне клиента.
3. Сторона клиента получает этот идентификатор функции, находит эту объекту функции, вызывает ее и отправляет обратно на сторону сервера в соответствии с идентификатором обратного вызова, данным стороной сервера.
4. Сторона сервера получает результат, находит функцию обратного вызова, продолжает выполнять и завершается.
Метод записи функции может быть завершен другими способами. Общая идея состоит в том, чтобы заменить функцию на что -то сериализуемое, чтобы функцию можно было найти локально при вызове на удаленной стороне. Вы можете обратиться к реализации DNODE.