int main(int argc, char* argv[])
{
  try
  {
    // initialize logging - this reads the file log.xml from the current directory
    log_init();

    // read the command line options
    cxxtools::Arg<std::string> ip(argc, argv, 'i');  // option -i <ip-addres> defines the address where to find the server
    cxxtools::Arg<bool> binary(argc, argv, 'b');
    cxxtools::Arg<bool> json(argc, argv, 'j');
    cxxtools::Arg<bool> jsonhttp(argc, argv, 'J');
    cxxtools::Arg<std::size_t> timeout(argc, argv, 't', cxxtools::RemoteClient::WaitInfinite);
    cxxtools::Arg<unsigned short> port(argc, argv, 'p', binary ? 7003 : json ? 7004 : 7002);

    // we need a selector, which controls the network activity
    cxxtools::Selector selector;

    // Normally we would define just one rpc client for the protocol we use but
    // here we want to demonstrate, that it is just up to the client, which protocol
    // is used for the remote call.

    // One client can run just one request at a time. To run parallel requests
    // we need 2 clients. So we define 2 clients for each protocol.

    // define a xlmrpc client
    cxxtools::xmlrpc::HttpClient xmlrpcClient1(selector, ip, port, "/xmlrpc");
    cxxtools::xmlrpc::HttpClient xmlrpcClient2(selector, ip, port, "/xmlrpc");

    // and a binary rpc client
    cxxtools::bin::RpcClient binaryClient1(selector, ip, port);
    cxxtools::bin::RpcClient binaryClient2(selector, ip, port);

    // and a tcp json rpc client
    cxxtools::json::RpcClient jsonClient1(selector, ip, port);
    cxxtools::json::RpcClient jsonClient2(selector, ip, port);

    // and a http json rpc client
    cxxtools::json::HttpClient httpJsonClient1(selector, ip, port, "/jsonrpc");
    cxxtools::json::HttpClient httpJsonClient2(selector, ip, port, "/jsonrpc");

    // now se select the client depending on the command line flags

    cxxtools::RemoteClient& client1(
        binary   ? static_cast<cxxtools::RemoteClient&>(binaryClient1) :
        json     ? static_cast<cxxtools::RemoteClient&>(jsonClient1) :
        jsonhttp ? static_cast<cxxtools::RemoteClient&>(httpJsonClient1) :
                   static_cast<cxxtools::RemoteClient&>(xmlrpcClient1));

    cxxtools::RemoteClient& client2(
        binary   ? static_cast<cxxtools::RemoteClient&>(binaryClient2) :
        json     ? static_cast<cxxtools::RemoteClient&>(jsonClient2) :
        jsonhttp ? static_cast<cxxtools::RemoteClient&>(httpJsonClient2) :
                   static_cast<cxxtools::RemoteClient&>(xmlrpcClient2));

    // define remote procedure with dobule return value and two double parameters
    cxxtools::RemoteProcedure<double, double, double> add1(client1, "add");
    cxxtools::RemoteProcedure<double, double, double> add2(client2, "add");

    // initiate the execution of our method
    add1.begin(5, 6);
    add2.begin(1, 2);

    // Calling RemoteProcedure::end will run the underlying event loop until
    // the remote procedure is finished and return the result.
    // In case of a error, an exception is thrown.

    // Note that waiting for the end of one remote procedure will also start
    // and maybe finish the second remote procedure.

    double result1 = add1.end(timeout);

    std::cout << "result1=" << result1 << std::endl;

    // Here we run the loop again until the second procedure is finished. It
    // may well be, that the procedure is already finished and we get the
    // result immediately.

    double result2 = add2.end(timeout);

    std::cout << "result2=" << result2 << std::endl;

  }
  catch (const std::exception& e)
  {
    std::cerr << "error: " << e.what() << std::endl;
  }
}
int main(int argc, char* argv[])
{
  try
  {
    log_init("rpcbenchclient.properties");

    cxxtools::Arg<std::string> ip(argc, argv, 'i');
    cxxtools::Arg<unsigned> threads(argc, argv, 't', 4);
    cxxtools::Arg<unsigned> concurrentRequestsPerThread(argc, argv, 'c', 4);
    cxxtools::Arg<bool> xmlrpc(argc, argv, 'x');
    cxxtools::Arg<bool> binary(argc, argv, 'b');
    cxxtools::Arg<bool> json(argc, argv, 'j');
    cxxtools::Arg<bool> jsonhttp(argc, argv, 'J');
    cxxtools::Arg<unsigned short> port(argc, argv, 'p', binary ? 7003 : json ? 7004 : 7002);
    BenchClient::numRequests(cxxtools::Arg<unsigned>(argc, argv, 'n', 10000));
    BenchClient::vectorSize(cxxtools::Arg<unsigned>(argc, argv, 'v', 0));
    BenchClient::objectsSize(cxxtools::Arg<unsigned>(argc, argv, 'o', 0));

    if (!xmlrpc && !binary && !json && !jsonhttp)
    {
        std::cerr << "usage: " << argv[0] << " [options]\n"
                     "options:\n"
                     "   -l ip      set ip address of server (default: localhost)\n"
                     "   -p number  set port number of server (default: 7002 for http, 7003 for binary and 7004 for json)\n"
                     "   -x         use xmlrpc protocol\n"
                     "   -b         use binary rpc protocol\n"
                     "   -j         use json rpc protocol\n"
                     "   -J         use json rpc over http protocol\n"
                     "   -c number  concurrent request per thread (default: 4)\n"
                     "   -t number  set number of threads (default: 4)\n"
                     "   -n number  set number of requests (default: 10000)\n"
                     "one protocol must be selected\n"
                  << std::endl;
        return -1;
    }

    BenchClients clients;

    XmlRpcClientCreator xmlRpcClientCreator(ip, port, "/xmlrpc");
    JsonHttpClientCreator jsonHttpClientCreator(ip, port, "/jsonrpc");
    JsonRpcClientCreator jsonRpcClientCreator(ip, port);
    BinRpcClientCreator binRpcClientCreator(ip, port);
    ClientCreator& clientCreator = binary   ? static_cast<ClientCreator&>(binRpcClientCreator)
                                 : json     ? static_cast<ClientCreator&>(jsonRpcClientCreator)
                                 : jsonhttp ? static_cast<ClientCreator&>(jsonHttpClientCreator)
                                 :            static_cast<ClientCreator&>(xmlRpcClientCreator);

    while (clients.size() < threads)
    {
      clients.push_back(new BenchClient(clientCreator, concurrentRequestsPerThread));
    }

    cxxtools::Clock cl;
    cl.start();

    for (BenchClients::iterator it = clients.begin(); it != clients.end(); ++it)
      (*it)->start();

    for (BenchClients::iterator it = clients.begin(); it != clients.end(); ++it)
      (*it)->join();

    cxxtools::Timespan t = cl.stop();

    std::cout << BenchClient::numRequests() << " requests in " << t.totalMSecs()/1e3 << " s => " << (BenchClient::requestsStarted() / (t.totalMSecs()/1e3)) << "#/s\n"
              << BenchClient::requestsFinished() << " finished " << BenchClient::requestsFailed() << " failed" << std::endl;

    for (BenchClients::iterator it = clients.begin(); it != clients.end(); ++it)
      delete *it;
  }
  catch (const std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }
}