mirror of
https://github.com/haiwen/libsearpc.git
synced 2025-09-18 16:07:05 +00:00
first commit
This commit is contained in:
212
README
Executable file
212
README
Executable file
@@ -0,0 +1,212 @@
|
||||
|
||||
Introduction
|
||||
======
|
||||
|
||||
Searpc is a simple C language RPC framework based on GObject system. Searpc
|
||||
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:
|
||||
|
||||
* **ret**: the return value of the RPC function
|
||||
* **err_code**: error code. This field is only set if the RPC function
|
||||
reports an error.
|
||||
* **err_msg**: error message. This field is only set if the RPC function
|
||||
reports an error.
|
||||
|
||||
Example
|
||||
======
|
||||
|
||||
Client
|
||||
------
|
||||
|
||||
In the client side, you need to:
|
||||
|
||||
* Define your RPC function with the our marco.
|
||||
* write code to send the request to server and get the resonpse from it.
|
||||
|
||||
|
||||
### Define your RPC function ###
|
||||
|
||||
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:
|
||||
|
||||
/*
|
||||
* 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_demo_int__string)
|
||||
|
||||
/* create an rpc_client and supply the transport function. */
|
||||
SearpcClient *rpc_client;
|
||||
rpc_client = searpc_client_new();
|
||||
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.
|
||||
|
||||
|
||||
### Transport function ###
|
||||
|
||||
When the client-side function is called, Searpc does the following work:
|
||||
|
||||
* Pack the function name and the params into JSON data format.
|
||||
* Call your transport function to send the JSON data
|
||||
to the server, and get the returned data from the server.
|
||||
* Unpack the returned JSON data and return the value as the return
|
||||
value of the client-side function.
|
||||
|
||||
Your transport function is supposed to:
|
||||
|
||||
* Send the request data to the server.
|
||||
* Receive the returned data from the server.
|
||||
|
||||
The prototype of the transport function is:
|
||||
|
||||
/*
|
||||
* arg: rpc_client->arg. Normally a socket number.
|
||||
* fcall_str: the JSON data stream generated by Searpc.
|
||||
* fcall_len: the length of **`fcall_str`**.
|
||||
* ret_len: place to get the length of the returned json data stream.
|
||||
* Returns: the JSON data stream ready for transporting.
|
||||
*/
|
||||
static char *transport_callback (void *arg, const char *fcall_str, size_t fcall_len, size_t *ret_len);
|
||||
|
||||
|
||||
Server
|
||||
------
|
||||
|
||||
In the server side, you need to:
|
||||
|
||||
* Register your function
|
||||
* write code to receive the request and send the result
|
||||
|
||||
And Searpc handles the others for you.
|
||||
|
||||
### Concepts ###
|
||||
|
||||
* **`Marshal`**: The process of packing the result of the RPC function
|
||||
into JSON data format stream is called marshalling, and 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.
|
||||
|
||||
|
||||
### Register your function ###
|
||||
|
||||
The **`seaprc_server_register_function`** routine registers a function as
|
||||
a RPC function. It inserts your function into the function table. The
|
||||
prototype of this function is:
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
Before calling **`searpc_server_register_function`**, you need to call
|
||||
**`searpc_server_init()`** to do the initialization work.
|
||||
|
||||
|
||||
### Call the RPC fucntion ###
|
||||
|
||||
After the registration, you should listen to the socket and wait for the
|
||||
incoming request data stream. Once you get a valid request, call the
|
||||
**`searpc_server_call_function()`** routine, which will automatically do 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.
|
||||
* 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:
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
The value returned by **`searpc_server_call_function()`** is the JSON data
|
||||
ready for transportation, which you can send to the client directly.
|
||||
|
||||
In the client side, Searpc would unpack the data stream and return the value
|
||||
contained within it as the return value of the client-side RPC function defined
|
||||
in the macro **`SEARPC_CLIENT_DEFUN_XXX__YYY()`**.
|
||||
|
||||
|
||||
Pysearpc
|
||||
======
|
||||
|
||||
**Pysearpc** is the Python binding of **Searpc**. Only the client side function is
|
||||
supported. To use it, simply define a class which inherits **SearpcClient**, and
|
||||
provide a **`call_remote_func_sync`** method, which is equivalent to the
|
||||
**`transport_callback`**.
|
||||
|
||||
To define your RPC funtion, use the **`@searpc_func`** decorator. It is
|
||||
equivalent to **`SEARPC_CLIENT_DEFUN_XXX__YYY`** macro. To define a RPC
|
||||
function which accepts multiple params, here is an example:
|
||||
|
||||
class SampeSearpcClient(SearpcClient):
|
||||
def call_remote_func_sync(self, fcall_str):
|
||||
# your transport code here
|
||||
...
|
||||
|
||||
@searpc_func("int", ["string", "string"])
|
||||
def searpc_demo_func(self):
|
||||
# this is enough for the client side
|
||||
pass
|
||||
|
||||
See the demo program for a more detailed example.
|
||||
|
||||
|
||||
Demos
|
||||
======
|
||||
|
||||
There are well-commented demos in both C and Python.
|
||||
|
||||
* **searpc-demo-server.c**: The server side demo program
|
||||
* **searpc-demo-client.c**: The client side demo in C
|
||||
* **pysearpc-demo-client.py**: The client side demo in Python
|
||||
|
||||
To run the demo, run the server demo in a shell, and run the client demo(either
|
||||
the C or Python demo) in another.
|
||||
|
||||
|
||||
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.
|
Reference in New Issue
Block a user