YARP  2.3.68+228-20170410.2+git7d0b2e0
Yet Another Robot Platform
Specialized RPC ports
Author
Paul Fitzpatrick

RPC stands for "Remote Procedure Call", and in YARP is used to refer to communication that consists of a message and a reply to that message. Historically, YARP has stressed streaming communication (without replies) because in our experience it leads to more robust and scalable control logic. However, RPC definitely has its place, and this tutorial describes how to do it in YARP.

RPC using regular YARP ports

The basic mechanism for getting replies with YARP is described in the getting replies section of the Port Power tutorial. The RPC ports are a thin wrapper around regular ports, for the purpose of restricting flexibility rather than increasing it.

RPC using specialized YARP ports

If you intend to use ports for RPC alone, you can use the yarp::os::RpcClient and yarp::os::RpcServer classes. These are just like the regular yarp::os::Port class, except that streaming operation is prohibited. By using these classes, YARP can check for accidental misusage of the ports, and give more helpful error messages.

Here is an example server:

/*
* Copyright: (C) 2010 RobotCub Consortium
* Authors: Paul Fitzpatrick
* CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT
*/
/*
This is an example of using a specialized RpcServer port to receive
and reply to messages. Regular YARP ports can do this as well (see
summer.cpp), but use of RpcServer/RpcClient allows for better
run-time checking of port usage to catch mistakes.
*/
#include <yarp/os/all.h>
#include <stdio.h>
using namespace yarp::os;
int main(int argc, char *argv[]) {
if (argc<2) {
fprintf(stderr, "Please supply a port name for the server\n");
return 1;
}
const char *name = argv[1];
Network yarp;
RpcServer port;
port.open(name);
while (true) {
printf("Waiting for a message...\n");
Bottle cmd;
Bottle response;
port.read(cmd,true);
printf("Got message: %s\n", cmd.toString().c_str());
response.addString("you");
response.addString("said");
response.append(cmd);
printf("Sending reply: %s\n", response.toString().c_str());
port.reply(response);
}
}

And here is a client to go with it:

/*
* Copyright: (C) 2010 RobotCub Consortium
* Authors: Paul Fitzpatrick
* CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT
*/
/*
This is an example of using a specialized RpcClient port to send
messages and receive replies. Regular YARP ports can do this as well,
but use of RpcServer/RpcClient allows for better
run-time checking of port usage to catch mistakes.
*/
#include <yarp/os/all.h>
#include <stdio.h>
using namespace yarp::os;
int main(int argc, char *argv[]) {
if (argc<3) {
fprintf(stderr, "Please supply (1) a port name for the client\n");
fprintf(stderr, " (2) a port name for the server\n");
return 1;
}
Network yarp;
const char *client_name = argv[1];
const char *server_name = argv[2];
RpcClient port;
port.open(client_name);
int ct = 0;
while (true) {
if (port.getOutputCount()==0) {
printf("Trying to connect to %s\n", server_name);
yarp.connect(client_name,server_name);
} else {
Bottle cmd;
cmd.addString("COUNT");
cmd.addInt(ct);
ct++;
printf("Sending message... %s\n", cmd.toString().c_str());
Bottle response;
port.write(cmd,response);
printf("Got response: %s\n", response.toString().c_str());
}
}
}

The server and client communicate with yarp::os::Bottle objects here, but as usual anything that implements yarp::os::Portable can be used.

Monitoring RPC communication

Normal streaming communication in YARP is very easy to monitor, just connect another port to the sender. For RPC communication, we have to be a bit more careful.

Suppose the server and client above are running (the source code is in example/os/rpc_server.cpp and example/os/rpc_client.cpp), in two separate terminals, as follows:

./rpc_server /server
./rpc_client /client /server

Here we have named the server port /server and the client port /client. Every second or so, the client sends a message to the server with a count in it, and the server replies with "you said" followed by that message.

How can we monitor this traffic remotely? YARP supports a special kind of logging connection called log.in which can report all the inputs a port is receiving (along with the corresponding replies). We make a connection from the server (not the client) to a logging port, set the connection to log.in mode, and we are done.

The syntax for doing so is either:

yarp read /read tcp+log.in://server

Or equivalently:

yarp read /read
yarp connect /server /read tcp+log.in

The protocol in this case is specified to be tcp (which is the default), but with an added +log.in decoration. This is a "carrier modifier" that tells YARP that the connection has a special purpose, in this case to log traffic that arrives at the /server port. Without that modifier, this connection would be forbidden if the RPC server is already connected to a client, and even if it were allowed it would misbehave.

The output shown by the "yarp read" command will be something like this:

[rpc] (COUNT 29) (you said COUNT 29)
[rpc] (COUNT 30) (you said COUNT 30)
[rpc] (COUNT 31) (you said COUNT 31)
[rpc] (COUNT 32) (you said COUNT 32)
[rpc] (COUNT 33) (you said COUNT 33)
[rpc] (COUNT 34) (you said COUNT 34)
[rpc] (COUNT 35) (you said COUNT 35)
[rpc] (COUNT 36) (you said COUNT 36)

The first element is a tag for RPC traffic. The second element is a nested list describing the input received by the port. The third element is a nested list describing the corresponding output produced by the port.

Note that we log from the server side, because we are logging inputs. At this time YARP does not have a log.out mode for logging outputs with their replies.

The logging connection will pass along any envelope or timestamp associated with the input, and will lack an envelope if the input lacks an envelope.