This article mainly introduces node. the implementation principle of RPC (Remote process call) in js is introduced. This article is based on a simple RPC library nodejslight_rpc implementation. If you need a friend, refer to RPC (Remote process call ), that is, you can call the Program Method on the remote host locally and see a simple nodejs implementation to learn the RPC principle well: nodejs light_rpc
Example:
The Code is as follows:
// Server
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:
The Code is as follows:
// Client
Rpc. connect (5556, 'localhost', function (remote, conn ){
Remote. combine (1, 2, function (res ){
If (res! = 3 ){
Console. log ('error', res );
}
});
});
Let's briefly talk about the entire process:
1. Start the program on the server and listen on the port to implement the functions provided to the client (such as combine and multiply in the preceding example) and save them in an object.
2. The client starts the program and connects to the server. After the connection is complete, the describe command is sent, requiring the server to return the function name that can be called.
The Code is as follows:
Connection. on ('connect ', function (){
Connection. write (command (descrCmd ));
});
3. The server receives the describe command and packs the function names that can be called and sends them out ("combine", "multiply ")
4. the client receives the function name sent by the server, registers it to its own object, and packs a method for each function name so that the local call to these functions actually sends a request to the server:
The Code is as follows:
For (var p in cmd. data ){
RemoteObj [p] = getRemoteCallFunction (p, self. callbacks, connection );
// The implementation of getRemoteCallFunction can be found below
}
5. The client calls the server functions:
1) generate a unique ID for the incoming callback function, called callbackId, and record it to an object of the client.
2) wrap the following data and send it to the server: Call function name, JSON serialized parameter list, callbackId
The Code is as follows:
Function getRemoteCallFunction (callback name, 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 (partition name, {id: id, args: args });
Connection. write (newCmd );
}
}
6. The server receives the above information, parses the data, deserializes the parameter list, and calls the function based on the function name and parameter.
The Code is as follows:
Var args = cmd. data. args;
Args. push (getSendCommandBackFunction (c, cmd. data. id ));
Self. wrapper [cmd. command]. apply ({}, args );
7. After the function is run, serialize the result together with the previously received callbackId and send it back to the client.
The Code is as follows:
Function getSendCommandBackFunction (connection, consumer ID ){
Return function (){
Var innerArgs = parseArgumentsToArray. call ({}, arguments );
Var resultCommand = command (resultCmd, {id: Region id, args: innerArgs });
Connection. write (resultCommand );
};
}
8. The client receives the function running result and callbackId, extracts the callback function based on the callbackId, and transfers the running result to the callback function for execution.
9. The whole process is completed, see the source code: https://github.com/romulka/nodejs-light_rpc
Notes:
1. The client and server keep connected throughout the process. Unlike sending and receiving the http protocol, the connection is disconnected. Therefore, you cannot determine whether a data transfer is completed by disconnecting the connection. To determine whether the data is received, the client and server follow a simple protocol: add the length and separator of the data packet before the data. For example, the separator is \ n: [data packet length], so that after receiving the data, the length of the data packet is first taken out, and then the accumulated received data packets are constantly judged to be equal to or greater than this length. If this is the case, data transmission is completed once, you can start parsing and extracting data.
2. this RPC is simple because there is no function type in the parameter. For example, if a parameter is an object with a function member, the function is ignored during JSON serialization, this function cannot be executed on the server.
To solve this problem, complicated processing is required:
1. traverse each parameter to be sent to the remote end in depth, extract the function Member, generate a unique id for this function, put it in a local object, and replace this function member with this id string, and identifies the member as a function. In this way, the object can be serialized and sent out.
2. the server receives the call. When the function in the parameter object is used, it is determined that this is a function processed by the client. There is an id that is sent back to the client, send the callback function id to the client in the same way, and wait for the client to callback.
3. The client receives the function id, finds the function entity, calls it, and sends it back to the server based on the callback id sent by the server.
4. The server receives the result, finds the callback function, continues the execution, and completes.
The function recording method can be completed in other ways. The general idea is to replace the function with something that can be serialized, and record the function so that this function can be found locally when called by the remote end. See dnode implementation.