1
0
mirror of https://github.com/haiwen/libsearpc.git synced 2025-06-26 13:41:35 +00:00

Update README

This commit is contained in:
plt 2012-06-23 22:45:25 +08:00
parent c91f143fdc
commit ac753e04c7

View File

@ -6,10 +6,10 @@ handles the serialization/deserialization part of RPC, the transport
part is left to users.
The serialization/deserialization uses JSON format via json-glib
library. A JsonObject is returned from server to client after
executing the RPC function. Each RPC function defined in the server side should
take an extra GError argument to report error. The returned JsonObject
contains three fields:
library. A serialized json object is returned from server to client
after executing the RPC function. Each RPC function defined in the
server side should take an extra GError argument to report error. The
returned json object contains three fields:
* **ret**: the return value of 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:
* 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.
### Define your RPC function ###
### Create rpc_client ###
The client define RPC functions using macros defined in
`searpc-client.h`. To call the functions, the client needs to create
a SearpcClient object and supply a transport function. For example:
The client needs to create 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. */
SearpcClient *rpc_client;
@ -61,11 +54,25 @@ a SearpcClient object and supply a transport function. For example:
rpc_client->transport = transport_callback;
rpc_client->arg = &sockfd;
The `SEARPC_CLIENT_DEFUN_XXX__YYY` macro defines a client side RPC function.
**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,
`SEARPC_CLIENT_DEFUN_INT__STRING_STRING` defines a RPC function which takes two
string params and returns an integer value.
Suppose we have a `get_substring` function defined in server as follows:
gchar *get_substring (const gchar *orig_str, int sub_len, GError **error)
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 ###
@ -100,7 +107,8 @@ Server
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
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
pack the result is called a **marshal**.
* **Signature**: Signatures are used to identify different types of
marshals. After the execution of a RPC function on the server side,
different types of results need different marshals.
* **Function table**: The hash table used to store the (funcname, func)
pairs.
* **Marshal table**: The hash table used to store the (signature,
marshal) pairs.
* **Signature**: Every function has a signature determined by its
return type and parameter types. Knowning a function's signature
enable us to use a corresponding marshal to call it and convert
the result into json string.
### 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
a RPC function. It inserts your function into the function table. The
a RPC function. The
prototype of this function is:
/*
* service: the name of the service
* func: pointer to the function you want to register
* fname: the name of the function. It would be the key of your
* function in the fucntion hash table.
* signature: the identifier used to get the corresponding marshal.
* 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 ###
@ -150,23 +222,34 @@ incoming request data stream. Once you get a valid request, call the
following work for you:
* 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.
* Packing the result into a JSON data string.
The prototype of `searpc_server_call_function` is:
/*
* service: Service name.
* data: The incoming JSON data stream.
* len: The length of **`data`**.
* 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
*/
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
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
========
@ -207,21 +290,6 @@ demo in another. To run the python demo, you should first install the
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
==========