6.4. Introduction on using the Client APIs
6.4.1. Thread Safety
Thread safety is different between APIs:
When creating and configuring an LN client, this should always be done from a single thread.
The C and the C++ API is able to access the same port or service safely from multiple threads. In other words, the communication routines like port::read() and port::write are fully thread-safe.
In Python, any object of the LN client library, including port, packet and service objects, should normally only be accessed from a single thread. If access from multiple threads is needed, such objects should always be protected by a lock. To avoid the difficulties that are inherent with locking, it is often a better idea to separate the program into different processes which communicate via LN messages.
also, it is not possible to use
os.fork()orfork()in an LN client.
6.4.2. Python
class ln.client(client_name, args)
class ln.client(client_name, ln_manager=None)
6.4.2.1. Using the direct API for calling LN Services in Python
6.4.2.2. Using the direct API for calling LN services in C++
6.4.2.3. Service Clients: Wrapper Class and Service Objects
For the client, as we have seen in our service client example, the approach is similar, with the difference that we need to get a service client handle and to use methods and data members from that service client object. This works as follows:
First, we derive a class from the API class services_wrapper.
Then, we create a new client object, and initialize our derived class
with that object as a parameter:
class ElevatorServiceClient(ln.services_wrapper):
def __init__(self):
self.clnt = ln.client("elevator_service_client", sys.argv)
ln.services_wrapper.__init__(self, self.clnt, "elevator/elevator_service")
6.4.2.3.1. Client Objects
6.4.2.3.1.1. Methods: get_service()
The client object, that we already described, has a method which we
did not use so far, for the purpose of service communication. It is
called services_wrapper.get_service(). By calling this
method, we can create a new service client object:
elevator_svc = self.clnt.get_service("elevator/elevator_service.request_elevator",
"elevator/elevator_service/elevator_call")
This object is best stored as a class member, so that it does not need to be created repeatedly.
Again, the first parameter of the
services_wrapper.get_service() call is the name of the method
of the service provider which we are going to call. The second name
is the name of the message definition which is going to be used for
the call.
6.4.2.3.2. Service Objects
A service client handle can be used in a very similar way to the
port objects which we saw above. Its counterpart is a
service provider handle (which has technically the same type
as the client handle, but is configured differently).
6.4.2.3.2.1. Members
The service object has two data members, service.req and service.response,
corresponding to the “request” and the “response” part of the
service message definition.
6.4.2.3.2.2. Methods
The only method of the service object which we need here is the service.call()
method.
The client object can be used as follows:
elevator_svc.req.requested_floor = request_floor
elevator_svc.call()
response = elevator_svc.resp
First, the request input parameters are assigned to the
service.reqmembers, one for each element or member that the request part of the service message definition has.Second, the
service.call()method is invoked. This method blocks until the service call has returned and yielded a result.Finally, the result of the call can be read from the members of the
service.responseparameters of the service.
See also
Client Objects in the reference.
6.4.3. using the C/C++ binding
for C/C++ programs you need to include the “ln.h” header-file:
#include <ln/ln.h>
and you need to link against the libln-library. for this to work you need to tell your compiler and linker where to find those. in case of gcc/g++ it could look like this:
# compiling:
$ g++ -o my_program.o -c my_program.cpp -I${PREFIX}/include
# linking:
$ g++ -o my_program my_program.o -L${PREFIX}/lib/sled11-x86-gcc4.x -lln
6.4.3.1. ln_client constructor
c
/* C */
int ln_init(ln_client* clnt, const char* client_name,
int argc, char** argv);
int ln_init_to_manager(ln_client* clnt, const char* client_name,
const char* ln_manager);
C++
ln::client(std::string client_name);
ln::client(std::string client_name, int argc, char* argv[]);
ln::client(std::string client_name, std::string ln_manager);
ln::client(ln_client clnt);