Another router to router example

This is just a variation on the sample shown in the previous post. I am writing here a simple ZeroMQ router to router application where it is the server router having a predetermined identity.

The main thread spawns the client and server threads:
const char* server = "Server"; // 1
const int nClients = 3;

boost::thread_group threads;
for(int i =0; i < nClients; ++i)
    threads.create_thread(std::bind(rrClientS, server)); // 2

threads.create_thread(std::bind(rrServerS, server, nClients)); // 3
threads.join_all();
1. This is going to be the server socket identity.
2. Each client has to know which is the server id.
3. Pass the socket id and the number of clients to the server function.

Each client runs on this function:
void rrClientS(const char* server)
{
    dumpId("client startup");
    zmq::context_t context(1);

    std::string tid = boost::lexical_cast<std::string>(boost::this_thread::get_id()); // 1
    zmq::Socket skRouter(context, ZMQ_ROUTER, tid);
    skRouter.connect(SK_ADDR_CLI); // 2
    dumpId(SK_ADDR_CLI, server);

    boost::this_thread::sleep(boost::posix_time::seconds(1)); // 3
    skRouter.send(server, ""); // 4

    zmq::Frames frames = skRouter.blockingRecv(2); // 5
    dumpId("client shutdown");
}
1. There is no requirement for the client socket id, I use the thread id as a way to make the output more interesting.
2. Each client socket connects to the router server socket.
3. As in the previous example, but on the other way round. Now are the clients that have to wait till the server socket is ready before starting send messages. Waiting for a while is a simple but unreliable way to accomplish this requirement. For production code we should think about something more sensible.
4. Sending an "hello" message to the server. Notice that it is a two-framed one, first frame is the recipient id, second one is the payload. Actually here we need to let the server know the client id, so we can even send an empty payload.
5. Getting an answer from the server. We don't care much about it here, but it shows that the server can really send messages to the clients, once it gets their id.

And this is the server:
void rrServerS(const char* sid, int nClients)
{
    dumpId("server startup");
    zmq::context_t context(1);

    zmq::Socket skRouter(context, ZMQ_ROUTER, sid); // 1
    skRouter.bind(SK_ADDR_SRV);

    dumpId("server ready on", SK_ADDR_SRV);

    std::vector<std::string> clients; // 2
    clients.reserve(nClients);
    for(int i =0; i < nClients; ++i)
    {
        zmq::Frames in = skRouter.blockingRecv(2);
        dumpId("receiving from", in[0].c_str());
        clients.push_back(in[0]); // 3
    }

    std::for_each(clients.begin(), clients.end(), [&skRouter](std::string& client)
    {
        skRouter.send(client, ""); // 4
    });
    dumpId("server shutdown");
}
1. Create a ROUTER socket and set its id as specified.
2. To send messages to the clients, we need their id, we store them in this container.
3. We were interested just in the first frame, the client id, so that we can use it below to send it a message.
4. We send a message with an empty payload to each client, just to prove that we can.

Full C++ source code for this example and the one in the previous post is on github.

No comments:

Post a Comment