// include automatically generated code #include "t2nexample_common.hxx" LIBT2N_EXPORT std::string testfunc(std::string str) { // exceptions derived from libt2n::t2n_exception are passed to the client transparently if (str=="throw") throw libt2n::t2n_runtime_error("throw me around"); return str+", testfunc() was here"; }
#include <string> #include <boost/serialization/string.hpp>
#include <signal.h> #include <socket_server.hxx> #include <command_server.hxx> // for group_command_server // the automatically generated server side code (cmd_group_t2nexample class) #include "t2nexample_server.hxx" int main(int argc, char** argv) { // don't kill the server on broken pipe signal(SIGPIPE, SIG_IGN); // create local socket server (a.k.a "unix domain socket") // if you want to to create a tcp/ip server you pass the port to the constructor // (for details take a look at the socket_server class documentation) libt2n::socket_server ss("./socket"); libt2n::group_command_server<cmd_group_t2nexample> cs(ss); // handle requests while(true) cs.handle(); return 0; }
AC_INIT(configure.in) AM_INIT_AUTOMAKE(libt2n-example1, 0.1) AC_LANG_CPLUSPLUS AC_PROG_CXX AM_PROG_LIBTOOL dnl check for libt2n (library and code generator) LIBT2N_CHECK(libt2n >= 0.2) AC_OUTPUT(Makefile)
# not a GNU package. You can remove this line, if you have all needed files, that a GNU package needs AUTOMAKE_OPTIONS = foreign # our dependencies INCLUDES = @LIBT2N_CFLAGS@ LDADD = @LIBT2N_LIBS@ # list your command groups (seperated by spaces) CMDGROUPS = t2nexample # for each command group list the files to parse for LIBT2N_EXPORT t2nexample_GROUP = t2nexample.cpp # unfortunately we can't set those from variables (because they are parsed by automake) # for each group build a client library from generated source file(s) # (if you have automake >= 1.5 you might wish to use nodist_ here) # Note: the library name must match the group name libt2nexample_la_SOURCES = t2nexample_client.cpp lib_LTLIBRARIES = libt2nexample.la # build server program bin_PROGRAMS = libt2n-example1-server # (if you have automake >= 1.5 you might wish to use nodist_ here) # nodist_server_SOURCES = t2nexample_server.cpp libt2n_example1_server_SOURCES = \ server.cpp $(t2nexample_GROUP) \ t2nexample_server.cpp # include Makefile snippet doing all the magic include codegen.make
autoreconf -f -i && ./configure && make install
AC_INIT(configure.in) AM_INIT_AUTOMAKE(libt2n-example1-client, 0.1) AC_LANG_CPLUSPLUS AC_PROG_CXX AM_PROG_LIBTOOL dnl check for the client library PKG_CHECK_MODULES(T2NEXAMPLE, t2nexample = 0.1) AC_OUTPUT(Makefile)
# not a GNU package. You can remove this line, if you have all needed files, that a GNU package needs AUTOMAKE_OPTIONS = foreign INCLUDES = @T2NEXAMPLE_CFLAGS@ LDADD = @T2NEXAMPLE_LIBS@ bin_PROGRAMS = libt2n-example1-client libt2n_example1_client_SOURCES = client.cpp
// for socket_client_connection #include <socket_client.hxx> // include generated library header #include "t2nexample_client.hxx" int main(int argc, char** argv) { // use a local socket (a.k.a "unix domain socket") // if you want to connect to a tcp/ip server you pass the port and server name to the constructor libt2n::socket_client_connection sc("./socket"); // this generated class has a method for each of our exported procedures cmd_group_t2nexample_client cc(&sc); bool throwok=false; // exceptions are passed back to the client transparently try { // call the remote procedure (we pass "throw" to cause a exception to be thrown) cc.testfunc("throw"); } catch(libt2n::t2n_runtime_error &e) { throwok=(std::string(e.what())=="throw me around"); } // call remote procedure and check the return value is correct return ( throwok && ( cc.testfunc("hello") == "hello, testfunc() was here" ) ) ? EXIT_SUCCESS : EXIT_FAILURE; }
autoreconf -f -i && ./configure && make install
$ cd /tmp $ file socket socket: cannot open `socket' (No such file or directory) $ libt2n-example1-server & [1] 7711 $ file socket socket: socket $ libt2n-example1-client && echo ok ok $ kill %1 $ rm socket
The other feature that the Client-Wrapper provides is a connection-singleton. T2n (currently) only offers single-threaded servers. So if you use methods of a T2n-server in a program, you usually only want to maintain one common connection to this server - even if it is accessed from different parts/modules/classes/... of your program. The Client-Wrapper is initialized with a libt2n::ConnectionWrapper.
This libt2n::ConnectionWrapper takes the error-handling strategy (e.g. reconnect-then-throw) and everything needed to establish a connection (e.g. socket name or host and tcp-port) as parameters. A connection is established at the first actual request to the server and re-used for following requests. You don't need to pass around client-handles and the like to your classes or methods, finding the right wrapper is done via the global singleton created for each server-interface initialized for the wrapper.
This example shows how to use the Client-Wrapper:
// for a wrapped socket connection #include <socket_wrapper.hxx> // include generated library header #include "t2nexample_client.hxx" // define a type for more conveniant access typedef libt2n::T2nSingletonWrapper<cmd_group_t2nexample_client> wraptype; // static object which keeps the wrapper-singleton template<> std::auto_ptr<wraptype> wraptype::SingletonObject = std::auto_ptr<wraptype>(); // static object which keeps the connection template<> std::auto_ptr<libt2n::ConnectionWrapper> wraptype::WrappedConnection = std::auto_ptr<libt2n::ConnectionWrapper>(); int main(int argc, char** argv) { // tell the client-wrapper how to contact the server if a connection is requested wraptype::set_connection(std::auto_ptr<libt2n::ConnectionWrapper> (new libt2n::ReconnectSocketWrapper("./socket"))); // execute a function via t2n. The wrapper will open a connection to the server if none // exists or try to reconnect if the existing one doesn't answer std::cout << t2n_exec(&cmd_group_t2nexample_client::testfunc)("hello") << endl; return EXIT_SUCCESS; }
The details of the Client-Wrapper can be found in the libt2n::T2nSingletonWrapper, but beware, the code is full of ugly templates and template-construction-defines.
1.5.6