mirror of
https://github.com/haiwen/libsearpc.git
synced 2025-06-27 14:06:50 +00:00
Update README
This commit is contained in:
parent
c91f143fdc
commit
ac753e04c7
172
README.markdown
172
README.markdown
@ -6,10 +6,10 @@ handles the serialization/deserialization part of RPC, the transport
|
|||||||
part is left to users.
|
part is left to users.
|
||||||
|
|
||||||
The serialization/deserialization uses JSON format via json-glib
|
The serialization/deserialization uses JSON format via json-glib
|
||||||
library. A JsonObject is returned from server to client after
|
library. A serialized json object is returned from server to client
|
||||||
executing the RPC function. Each RPC function defined in the server side should
|
after executing the RPC function. Each RPC function defined in the
|
||||||
take an extra GError argument to report error. The returned JsonObject
|
server side should take an extra GError argument to report error. The
|
||||||
contains three fields:
|
returned json object contains three fields:
|
||||||
|
|
||||||
* **ret**: the return value of the RPC function
|
* **ret**: the return value of the RPC function
|
||||||
* **err_code**: error code. This field is only set if the RPC function
|
* **err_code**: error code. This field is only set if the RPC function
|
||||||
@ -38,22 +38,15 @@ Client
|
|||||||
|
|
||||||
In the client side, you need to:
|
In the client side, you need to:
|
||||||
|
|
||||||
* Define your RPC function with our marco.
|
* Create a rpc_client and supply the transport function.
|
||||||
* write code to send the request to server and get the resonpse from it.
|
* write code to send the request to server and get the resonpse from it.
|
||||||
|
|
||||||
|
|
||||||
### Define your RPC function ###
|
### Create rpc_client ###
|
||||||
|
|
||||||
The client define RPC functions using macros defined in
|
The client needs to create a SearpcClient object and supply a
|
||||||
`searpc-client.h`. To call the functions, the client needs to create
|
transport function. For example:
|
||||||
a SearpcClient object and supply a transport function. For example:
|
|
||||||
|
|
||||||
/*
|
|
||||||
* define a RPC function which takes a string argument and returns
|
|
||||||
* an integer. The xxx_INT__STRING naming convention is used to
|
|
||||||
* indicate the types of the param(string) and the return value(int).
|
|
||||||
*/
|
|
||||||
SEARPC_CLIENT_DEFUN_INT__STRING(searpc_strlen)
|
|
||||||
|
|
||||||
/* create an rpc_client and supply the transport function. */
|
/* create an rpc_client and supply the transport function. */
|
||||||
SearpcClient *rpc_client;
|
SearpcClient *rpc_client;
|
||||||
@ -61,11 +54,25 @@ a SearpcClient object and supply a transport function. For example:
|
|||||||
rpc_client->transport = transport_callback;
|
rpc_client->transport = transport_callback;
|
||||||
rpc_client->arg = &sockfd;
|
rpc_client->arg = &sockfd;
|
||||||
|
|
||||||
The `SEARPC_CLIENT_DEFUN_XXX__YYY` macro defines a client side RPC function.
|
Suppose we have a `get_substring` function defined in server as follows:
|
||||||
**XXX** stands for the return type and **YYY** stands for the param type. If there
|
|
||||||
are multiple params, just append every param type there. For example,
|
gchar *get_substring (const gchar *orig_str, int sub_len, GError **error)
|
||||||
`SEARPC_CLIENT_DEFUN_INT__STRING_STRING` defines a RPC function which takes two
|
|
||||||
string params and returns an integer value.
|
To call this function, we type:
|
||||||
|
|
||||||
|
gchar* result;
|
||||||
|
GError *error = NULL;
|
||||||
|
result = searpc_client_call__string (client, "get_substring", &error,
|
||||||
|
2, "string", "hello", "int", 2);
|
||||||
|
|
||||||
|
`string` in `searpc_client_call__string` specify the return type. "get_substring"
|
||||||
|
is the function name. The remain parameters specify the number of parameters the rpc
|
||||||
|
function took and the type of each parameter and its value. So
|
||||||
|
|
||||||
|
2, "string", "hello", "int", 2
|
||||||
|
|
||||||
|
means "get_substring" takes 2 parameters, the first is of type "string", the value is
|
||||||
|
"hello", the second is of type "int", the value is 2.
|
||||||
|
|
||||||
|
|
||||||
### Transport function ###
|
### Transport function ###
|
||||||
@ -100,7 +107,8 @@ Server
|
|||||||
|
|
||||||
In the server side, you need to:
|
In the server side, you need to:
|
||||||
|
|
||||||
* Register your function
|
* Init searpc server
|
||||||
|
* Create services and register your functions
|
||||||
* write code to receive the request and send the result
|
* write code to receive the request and send the result
|
||||||
|
|
||||||
And Searpc handles the others for you.
|
And Searpc handles the others for you.
|
||||||
@ -112,34 +120,98 @@ And Searpc handles the others for you.
|
|||||||
data format is called marshalling. The function used to
|
data format is called marshalling. The function used to
|
||||||
pack the result is called a **marshal**.
|
pack the result is called a **marshal**.
|
||||||
|
|
||||||
* **Signature**: Signatures are used to identify different types of
|
* **Signature**: Every function has a signature determined by its
|
||||||
marshals. After the execution of a RPC function on the server side,
|
return type and parameter types. Knowning a function's signature
|
||||||
different types of results need different marshals.
|
enable us to use a corresponding marshal to call it and convert
|
||||||
|
the result into json string.
|
||||||
* **Function table**: The hash table used to store the (funcname, func)
|
|
||||||
pairs.
|
|
||||||
|
|
||||||
* **Marshal table**: The hash table used to store the (signature,
|
|
||||||
marshal) pairs.
|
|
||||||
|
|
||||||
|
|
||||||
### Register your function ###
|
### Init Searpc Server ###
|
||||||
|
|
||||||
|
First write rpc_table.py to contain the rpc function signatures as follows:
|
||||||
|
|
||||||
|
|
||||||
|
# [ <ret-type>, [<arg_types>] ]
|
||||||
|
func_table = [
|
||||||
|
[ "int", ["string"] ],
|
||||||
|
[ "string", ["int", "string"] ],
|
||||||
|
]
|
||||||
|
|
||||||
|
Add makefile rule:
|
||||||
|
|
||||||
|
searpc-signature.h searpc-marshal.h: rpc_table.py
|
||||||
|
python searpc-codegen.py rpc_table.py
|
||||||
|
|
||||||
|
`searpc-signature.h` and `searpc-marshal.h` will be created containing the
|
||||||
|
function signatures and corresponding marshals. `searpc-marshal.h` also contains
|
||||||
|
a function called `register_marshals`.
|
||||||
|
|
||||||
|
Then we init the server as follows:
|
||||||
|
|
||||||
|
|
||||||
|
#include "searpc-signature.h"
|
||||||
|
#include "searpc-marshal.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_rpc_service(void)
|
||||||
|
{
|
||||||
|
/* register_marshals is defined in searpc-marshal.h */
|
||||||
|
searpc_server_init(register_marshals);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
### Register Functions ###
|
||||||
|
|
||||||
|
To register a function we first need to create a service. A service is
|
||||||
|
a set of functions.
|
||||||
|
|
||||||
|
Suppose we want to make `searpc_strlen` callable from some network
|
||||||
|
clients, we can do this by putting the following code somewhere:
|
||||||
|
|
||||||
|
static int
|
||||||
|
searpc_strlen(const char *str)
|
||||||
|
{
|
||||||
|
if (str == NULL)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return strlen(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
register_functions()
|
||||||
|
{
|
||||||
|
|
||||||
|
searpc_create_service("searpc-demo");
|
||||||
|
|
||||||
|
/* The first parameter is the implementation function.
|
||||||
|
* The second parameter is the name of the rpc function the
|
||||||
|
* client would call.
|
||||||
|
* The third parameter is the signature.
|
||||||
|
*/
|
||||||
|
searpc_server_register_function("searpc-demo",
|
||||||
|
searpc_strlen,
|
||||||
|
"searpc_strlen",
|
||||||
|
searpc_signature_int__string());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
The `seaprc_server_register_function` routine registers a function as
|
The `seaprc_server_register_function` routine registers a function as
|
||||||
a RPC function. It inserts your function into the function table. The
|
a RPC function. The
|
||||||
prototype of this function is:
|
prototype of this function is:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* service: the name of the service
|
||||||
* func: pointer to the function you want to register
|
* func: pointer to the function you want to register
|
||||||
* fname: the name of the function. It would be the key of your
|
* fname: the name of the function. It would be the key of your
|
||||||
* function in the fucntion hash table.
|
* function in the fucntion hash table.
|
||||||
* signature: the identifier used to get the corresponding marshal.
|
* signature: the identifier used to get the corresponding marshal.
|
||||||
* Returns: a gboolean value indicating success or failure
|
* Returns: a gboolean value indicating success or failure
|
||||||
*/
|
*/
|
||||||
gboolean searpc_server_register_function (void *func, const gchar *fname, const gchar *signature)
|
gboolean searpc_server_register_function (const char *service,
|
||||||
|
void* func,
|
||||||
|
const gchar *fname,
|
||||||
|
gchar *signature);
|
||||||
|
|
||||||
Before calling `searpc_server_register_function`, you need to call
|
|
||||||
**`searpc_server_init()`** to do the initialization work.
|
|
||||||
|
|
||||||
|
|
||||||
### Call the RPC fucntion ###
|
### Call the RPC fucntion ###
|
||||||
@ -150,23 +222,34 @@ incoming request data stream. Once you get a valid request, call the
|
|||||||
following work for you:
|
following work for you:
|
||||||
|
|
||||||
* Parse the JSON data stream to resolve the function name and the data.
|
* Parse the JSON data stream to resolve the function name and the data.
|
||||||
* Lookup the function in the function table according to the funcname.
|
* Lookup the function in internal function table according to the funcname.
|
||||||
* If a proper function is found, call the function with the given params.
|
* If a proper function is found, call the function with the given params.
|
||||||
* Packing the result into a JSON data string.
|
* Packing the result into a JSON data string.
|
||||||
|
|
||||||
The prototype of `searpc_server_call_function` is:
|
The prototype of `searpc_server_call_function` is:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* service: Service name.
|
||||||
* data: The incoming JSON data stream.
|
* data: The incoming JSON data stream.
|
||||||
* len: The length of **`data`**.
|
* len: The length of **`data`**.
|
||||||
* ret_len: Place to hold the length of the JSON data stream to be returned
|
* ret_len: Place to hold the length of the JSON data stream to be returned
|
||||||
* Returns: The JSON data containing the result of the RPC
|
* Returns: The JSON data containing the result of the RPC
|
||||||
*/
|
*/
|
||||||
gchar* searpc_server_call_function (gchar *data, gsize len, gsize *ret_len)
|
gchar* searpc_server_call_function (const char *service,
|
||||||
|
gchar *data, gsize len, gsize *ret_len)
|
||||||
|
|
||||||
The value returned by `searpc_server_call_function()` is the JSON data
|
The value returned by `searpc_server_call_function()` is the JSON data
|
||||||
ready to send back to the client.
|
ready to send back to the client.
|
||||||
|
|
||||||
|
Note, the JSON data stream from client does not contain the service
|
||||||
|
name, it's left to the transport layer to solve the problem. There are
|
||||||
|
several ways, for example:
|
||||||
|
|
||||||
|
1. You may listen on different sockets and determine the service by
|
||||||
|
the incoming socket.
|
||||||
|
2. The client transport function prepend the service name into the request
|
||||||
|
before the json data, and the server transport function first read the service
|
||||||
|
name and read the json data.
|
||||||
|
|
||||||
Pysearpc
|
Pysearpc
|
||||||
========
|
========
|
||||||
@ -207,21 +290,6 @@ demo in another. To run the python demo, you should first install the
|
|||||||
package and setup the **PYTHONPATH** appropriately.
|
package and setup the **PYTHONPATH** appropriately.
|
||||||
|
|
||||||
|
|
||||||
Thread Safety
|
|
||||||
=============
|
|
||||||
|
|
||||||
|
|
||||||
Extend Searpc
|
|
||||||
=============
|
|
||||||
|
|
||||||
To support new rpc function types,
|
|
||||||
|
|
||||||
1. edit **`rpc_table.py`**,
|
|
||||||
2. call **make genrpc**.
|
|
||||||
3. If the return type is not supported yet, you need also define the
|
|
||||||
corresponding **`searpc_fret_*`** function.
|
|
||||||
|
|
||||||
|
|
||||||
Dependency
|
Dependency
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user