Design for Embodiment Communications Layer

From OpenCog


This page describes an obolete subsystem!. The code for this subsystem was deleted from github in 2015. This page remains here, as an archived historical record of something that once was in place.

Design for Embodiment Communications Layer

The communication layer of the Embodiment system abstracts and is the standard for how messages are passed throughout the embodiment system.

The basic class of communications layer is a NetworkElement (NE). The idea here is that every entity (namely, every process or CogServer, such as the OAC and LearningServer) in the Embodiment network should have a NetworkElement member to connect and exchange information with other entities.

 class NetworkElement {
    NetworkElement(string& myId, string& ipAddress, int portNumber);
    void sendMessage(Message& message);
    bool haveUnreadMessage();
    void retrieveMessages(int limit);
    unsigned int getIncomingQueueSize();
    Message* popIncomingQueue();

The Router is a central component to the architecture and acts as a hub for all NetworkElements. The NE's constructor handshakes with the Router to join the Embodiment network. The passed ID will be used by other Embodiment elements to contact this NE and exchange messages with it. The passed IP and port numbers will be used to perform this communication. The constructor will start a new thread to listen to the passed port in order to receive and queue the messages as they arrive. Note that the listener must be ready accept several sockects. Although it is only connected to the Router the latter is gonna request at least 2 sockets, one for Data (messages, etc) and one for Control (notifications of availability of the other NEs).

Handshaking is also used to retrieve any queued message due to any communications failure (due to temporary problems in network connection, for example).

Once inside the Embodiment network, this NE may use communication methods to exchange messages with other elements in the net.

  • sendMessage() post a message to given target ID, specified inside the message. The method returns once the Message is stored inside the router (not necessarily after the receiver read it)
  • haveUnreadMessage() return true if NE have at least one unread message, false otherwise (unread messages in Router's queue, waiting to be downloaded)
  • retrieveMessages() send a request to Router asking for unread messages (targeted to this NE); a "limit" parameter may be supplied to indicate the maximum number of messages which should be downloaded. Note that the download process is done when Router starts sending the messages. So, this is done by the thread that listens to the NE port.
  • getIncomingQueueSize() informs the size of the incoming queue or, in other words, how many messages were downloaded from Router and are waiting to be processed.
  • popIncomingQueue() must be called to get a message from the incoming queue when the NE want to process it.

A Message is simply a container interface:

 class Message {
    string from;
    string to;
    int type;
    virtual const char* getPlainTextRepresentation() = 0;
    virtual void loadPlainTextRepresentation(const char *strMessage) = 0;

Actual implementations should provide methods to map from/to c-style (char *) representation of the message.

The Router is expected to run at a specific IP and port number, thus every NetworkElement may contact it during its startup.

All Messages are sent through the Router, which keep a list with the IP/port of each service in the Embodiment network and a message queue for each NetworkElement. Router is responsible for receiving and storing all the messages sent by other NEs and delivering them as requested. On arrival of a message to a given NE, this element is notified so it can wake up (in the case it is sleeping) or request for receiving the unread messages.

This approach may sound like overkill, introducing the extra communication overhead of having every message passing through Router but it has the strong advantage of minimizing the number of lost messages in the case of any server crash. The bet here is that the communication overhead will not be relevant given the complexity of the requests. Of course this assumption may be wrong so one of the first things we'll do after the architectural prototype is up is to perform a load test in OAC to verify how well this architecture manages perceptions (by far the most relevant "communication load source" in PetBrain).

Note: The eventual goal is to remove the Router bottleneck and drop XML messages in strings in favour of ZeroMQ and Protocol Buffers.