6. Running Multiple Servers Using The Distributed Subsystem

Let’s try to launch both of the lobby server and the game server at the same time.

6.1. Enabling the distributed subsystem

If we run the programs on different servers, we can skip this step. Otherwise, we need to tweak their MANIFEST.json to prevent listening ports conflicts. Also, we need to turn on iFun Engine’s distribution feature.

Update hello_world-source/src/MANIFEST.game.json like this:

...
"tcp_json_port": 9012,
...
"http_json_port": 9018,
...
"api_service_port": 9014
...
"rpc_enabled": true,
"rpc_port": 9015,
...

Since the lobby server will use the default ports, it only need to enable the distributed subsystem. Update hello_world-source/src/MANIFEST.lobby.json like this:

...
"rpc_enabled": true,
...

Finally, iFun Engine relies on Apache Zookeeper for its distributed subsystem. If Zookeeper hasn’t been installed, yet, please install.

$ sudo apt-get install zookeeper zookeeperd

Tip

If zookeeper is running on other server, you should also update zookeeper_nodes field in the MANIFEST.json files.

6.2. Adding client messages for a test purpose

We will handle client messages signin and check to emulate player login and login status check. Please add the code below into hello_world-src/src/event_handlers.cc.

// This handler signs in a user named ``ifun``.
void OnSignin(const Ptr<Session> &session, const Json &message) {
  bool r = AccountManager::CheckAndSetLoggedIn("ifun", session);
  Json response;
  response["result"] = r;
  session->SendMessage("singin_reply", response);
}

// This handler checks if the ``ifun`` user has signed in.
// If signed in, a hosting server's uuid will be returned.
// Otherwise, Null UUID will be returned.
void OnCheck(const Ptr<Session> &session, const Json &message) {
  Rpc::PeerId server_id = AccountManager::Locate("ifun");
  Json response;
  response["result"] = boost::lexical_cast<string>(server_id);
  session->SendMessage("check_reply", response);
}


void RegisterEventHandlers() {
  ...
  HandlerRegistry::Register("signin", OnSignin);
  HandlerRegistry::Register("check", OnCheck);
  ...
}

OK. We’re ready to go. According to the configuration above, the lobby server will listen at the port of 8018 and the game server will do at 9018. Start each server with a matching run script.

# From the first terminal window
$ ./hello_world.lobby-local
# From the second terminal window
$ ./hello_world.game-local

6.3. Testing the distributed subsystem feature

Let’s send a signin message to the lobby server (i.e. port 8018) to make ifun sign in.

$ wget -qO- --post-data="{}" http://localhost:8018/v1/messages/signin
{"result":true,"_sid":"497844e8-1885-40ed-b7d7-29f2931ddac2","_msgtype":"singin_reply"}

We get true as expected. Let’s try a duplicated log in by issuing the same command one more time.

$ wget -qO- --post-data="{}" http://localhost:8018/v1/messages/signin
{"result":false,"_sid":"f0a511c0-ad16-4b1b-917f-f86da7809814","_msgtype":"singin_reply"}

The result is false for already signed in. Then how about sending a signin to the game server?

$ wget -qO- --post-data="{}" http://localhost:9018/v1/messages/signin
{"result":false,"_sid":"52a48a4a-58ef-462c-a08b-92371d298382","_msgtype":"singin_reply"}

This shows that the game server has also seen the user signed in. Then, let’s verify if the two servers share the whereabout the user. Send a check message to each server.

$ wget -qO- --post-data="{}" http://localhost:8018/v1/messages/check
{"result":"aa561332-8aad-4f1f-0000-000000000000","_sid":"622e4ae2-3793-41ac-97ab-708840416a6d","_msgtype":"check_reply"}

$ wget -qO- --post-data="{}" http://localhost:9018/v1/messages/check
{"result":"aa561332-8aad-4f1f-0000-000000000000","_sid":"8bff8116-5583-40f7-b363-c18929ac9400","_msgtype":"check_reply"}

We could see that both server returned the same server ID. So, user login information seems to be shared among servers correctly.

We are done evaluating iFun Engine’s distribution systems. We will discuss about its packaging feature and REST API feature in the next chapter.