Skip to main content
Skip table of contents

Writing a Greeter Server in C++

This page presents how to create a C++ server that implements our greeter interface and hosts it for clients to call.

Our server is comprised of 3 files:

  • Chatbot.h: This file defines a servant that implements Slice interface Greeter…

  • Chatbot.cpp: … and this file provides the concrete implementation for it.

  • Server.cpp: This file contains the main server program.

You can see the fully put together application on GitHub in the ice-demos repository.

Servant Implementation

First, we need to define our Chatbot servant that implements the Greeter Slice interface. Because the servant is so small and simple, we’ll look at the complete file, then explain it piece by piece:

CPP
#include "Greeter.h"

namespace Server
{
    /// Chatbot is an Ice servant that implements Slice interface Greeter.
    class Chatbot : public VisitorCenter::Greeter
    {
    public:
        // Implements the pure virtual function in the base class
        // (VisitorCenter::Greeter) generated by the Slice compiler.
        std::string greet(std::string name, const Ice::Current&) override;
    };
}

At the top, notice that we include Greeter.h; this is the header file that the Slice compiler generated from Greeter.ice. Then, we open a namespace named Server. This isn’t necessary for everything to work, but is considered a best practice.

More importantly, it’s here that we define the Chatbot class. There are two things that matter here:

  1. It inherits from VisitorCenter::Greeter. This is a ‘servant skeleton’ class that the Slice compiler generated from the Greeter Slice interface which (among other things) declares pure virtual functions corresponding to each mapped Slice operation for the Greeter interface.

  2. Chatbot provides concrete implementations for each of the mapped Slice operations. It’s permissible (and normal) for servants to contain other helper functions and fields as well, but at a minimum, it must implement functions whose signatures exactly match those in the skeleton.

Next, let’s look at Chatbot.cpp, which provides those concrete implementations.
It starts out with some includes and a using namespace std, but this is just boilerplate.

CPP
#include "Chatbot.h"

#include <iostream>
#include <sstream>

using namespace std;

What really matters in this file is that it provides an implementation of Chatbot::greet:

CPP
string
Server::Chatbot::greet(string name, const Ice::Current&)
{
    cout << "Dispatching greet request { name = '" << name << "' }" << endl;

    ostringstream os;
    os << "Hello, " << name << "!";
    return os.str();
}

You can see it takes a name parameter, and returns a greeting based on the provided name.

That’s all it takes to implement our servant!

Main Server Program

Server.cpp starts by including a few files:

  • Chatbot.h: Like we said above, this contains our servant definition.

  • Ice/Ice.h: This header provides definitions that are necessary for accessing the Ice runtime.

  • iostream: So the server can use cout to print to the console.

We also add a using declaration for the std namespace to reduce clutter:

CPP
#include "Chatbot.h"

#include <Ice/Ice.h>
#include <iostream>

using namespace std;

Next, we define the main function which will run the server:

CPP
int
main(int argc, char* argv[])
{
    // CtrlCHandler is a helper class that handles Ctrl+C and similar signals.
    // It must be constructed at the beginning of the program,
    // before creating an Ice communicator or starting any thread.
    Ice::CtrlCHandler ctrlCHandler;

    // ...

Unlike clients, we don’t want our server to exit until it’s explicitly told to shutdown. While there’s a variety of ways to accomplish this, for this example, our server will continue running until interrupted with Ctrl-C or a similar signal. To do this, we create a CtrlCHandler object to let us catch Ctrl-C and similar signals. When the server receives such a signal, it will shut down it’s communicator (more on that in a bit), which in turn makes waitForShutdown return. You can see this at the bottom of the main function:

CPP
    // ...

    // Shut down the communicator when the user presses Ctrl+C.
    ctrlCHandler.setCallback(
        [communicator](int signal)
        {
            cout << "Caught signal " << signal << ", shutting down..." << endl;
            communicator->shutdown();
        });

    // Wait until the communicator is shut down.
    // Here, this occurs when the user presses Ctrl+C.
    communicator->waitForShutdown();

This is largely just boilerplate though. The interesting part happens in between these two sections.
First, we create a Communicator and place it in a CommunicatorHolder, which ensures it will be properly destroyed when it goes out of scope:

CPP
    // Create an Ice communicator.
    // We'll use this communicator to create an object adapter.
    Ice::CommunicatorPtr communicator = Ice::initialize(argc, argv);

    // Make sure the communicator is destroyed at the end of this scope.
    Ice::CommunicatorHolder communicatorHolder{communicator};

Next we create an object adapter to register our servant with. In this example, our adapter is named GreeterAdapter and we have it listen on the following endpoint: tcp -p 4061, i.e. our adapter will listen for TCP requests on port 4061.

CPP
    // Create an object adapter that listens for incoming requests
    // and dispatches them to servants.
    auto adapter = communicator->createObjectAdapterWithEndpoints(
        "GreeterAdapter", "tcp -p 4061");

Then we register our Chatbot servant with this adapter under the identity greeter:

CPP
    // Register the Chatbot servant with the adapter.
    adapter->add(make_shared<Server::Chatbot>(), Ice::Identity{"greeter"});

And finally, we activate on our object adapter to start accepting incoming connections and dispatching requests from them:

CPP
    // Start dispatching requests.
    adapter->activate();
    cout << "Listening on port 4061..." << endl;
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.