Support multiple endpoints per socket

Sent messages will be scheduled among the endpoints according to socket
type: PUB will send the same data to all endpoints simultaneously, PUSH
will do round robin transfer.
Incoming data is fair queued between endpoints.

This is a feature of at least zeromq and nanomsg.

_____________
To use: in the device configuration, instead of specifying just one address,
specify a comma separated list e.g.

tcp://localhost:123,ipc:///tmp/socket

the connection method (bind/connect) applies to all endpoints in this case.
______________
Mixing binding and connecting endpoints is supported:
prefix "@" means "bind", "+" (or ">") means connect, e.g.

+tcp://localhost:123,@ipc:///tmp/socket,ipc:///tmp/asd

(in case of missing prefix, the default channel method is used for that
endpoint).
This commit is contained in:
mkrzewic
2016-11-11 16:35:23 +01:00
parent 0a3f14c0e3
commit c2d7c49cf5
6 changed files with 226 additions and 58 deletions

View File

@@ -411,39 +411,52 @@ bool FairMQChannel::ValidateChannel()
}
else
{
// check if address is a tcp or ipc address
if (fAddress.compare(0, 6, "tcp://") == 0)
//TODO: maybe cache fEndpoints as a class member? not really needed as tokenizing is
//fast, and only happens during (re-)configure
std::vector<std::string> fEndpoints;
Tokenize(fEndpoints, fAddress);
for (const auto endpoint : fEndpoints)
{
// check if TCP address contains port delimiter
string addressString = fAddress.substr(6);
if (addressString.find(":") == string::npos)
std::string address;
if (endpoint[0]=='@'||endpoint[0]=='+'||endpoint[0]=='>') {
address = endpoint.substr(1);
} else {
address = endpoint;
}
// check if address is a tcp or ipc address
if (address.compare(0, 6, "tcp://") == 0)
{
// check if TCP address contains port delimiter
string addressString = address.substr(6);
if (addressString.find(":") == string::npos)
{
ss << "INVALID";
LOG(DEBUG) << ss.str();
LOG(ERROR) << "invalid channel address: \"" << address << "\" (missing port?)";
return false;
}
}
else if (address.compare(0, 6, "ipc://") == 0)
{
// check if IPC address is not empty
string addressString = address.substr(6);
if (addressString == "")
{
ss << "INVALID";
LOG(DEBUG) << ss.str();
LOG(ERROR) << "invalid channel address: \"" << address << "\" (empty IPC address?)";
return false;
}
}
else
{
// if neither TCP or IPC is specified, return invalid
ss << "INVALID";
LOG(DEBUG) << ss.str();
LOG(ERROR) << "invalid channel address: \"" << fAddress << "\" (missing port?)";
LOG(ERROR) << "invalid channel address: \"" << address << "\" (missing protocol specifier?)";
return false;
}
}
else if (fAddress.compare(0, 6, "ipc://") == 0)
{
// check if IPC address is not empty
string addressString = fAddress.substr(6);
if (addressString == "")
{
ss << "INVALID";
LOG(DEBUG) << ss.str();
LOG(ERROR) << "invalid channel address: \"" << fAddress << "\" (empty IPC address?)";
return false;
}
}
else
{
// if neither TCP or IPC is specified, return invalid
ss << "INVALID";
LOG(DEBUG) << ss.str();
LOG(ERROR) << "invalid channel address: \"" << fAddress << "\" (missing protocol specifier?)";
return false;
}
}
// validate socket buffer size for sending
@@ -770,3 +783,27 @@ FairMQChannel::~FairMQChannel()
delete fCmdSocket;
delete fPoller;
}
void FairMQChannel::Tokenize(std::vector<std::string>& output,
const std::string& input,
const std::string delimiters)
{
using namespace std;
size_t start = 0;
size_t end = input.find_first_of(delimiters);
if (end == string::npos)
{
output.push_back(input.substr(start, input.length()));
}
else do
{
output.push_back(input.substr(start, end-start));
start = ++end;
end = input.find_first_of(delimiters, start);
if (end == string::npos)
{
output.push_back(input.substr(start, input.length()));
}
} while (end != string::npos);
}