Aim
This is an example to show how to use multicast to deliver a "non stop" sending server. This class is supported Linux.
Logic
In this example, we first have 2 servers. There is a way for them to select the primary server and send out the multicast data. On the above picture, Server 2 is the primary.
After several seconds in our example, we will turn off Server 2. They will then select the primary server again. There is a chance for Server 2 to become primary again but mostly Server 1 will take the role faster.
Source
#include <iostream>
#include <string.h>
#include <thread>
#include <chrono>
#include <atomic>
#include "MCastArbitrator.h"
#include "Logger.h"
#include "LinuxThread.h"
// usgae: ./MCastArbitrator
std::string MCastAddress = "225.1.32.28";
short MCastPort = 6000;
std::string SenderIP = "192.168.1.208";
class Sender : public LinuxThread
{
public:
Sender() { m_running = true; }
~Sender() { stopThread(); m_running = false; joinThread(); }
bool InitComponent(int instance) { m_instance = instance; startThread(); return true; }
void ChangeStatusForTest() { MCArbi.ChangeStatus(MCastArbitrator::MCArbiStatus::SECONDARY); }
private:
// override
void *Main()
{
std::vector<char> sendData;
if (MCArbi.InitComponent(SenderIP, MCastPort, 32, m_instance) == MCastArbitrator::MCArbiStatus::SUCCESS)
{
MCArbi.JoinGroup(MCastAddress);
sendData.resize(4);
int count = 0;
while(m_running.load())
{
memcpy(&sendData[0], &count, sizeof(int));
MCastArbitrator::MCArbiStatus retStatus = MCArbi.Send(&sendData[0], sizeof(int));
if (retStatus == MCastArbitrator::MCArbiStatus::SUCCESS)
{
LOGMSG_MSG("Send success! count: %d instance: %d\n", count, m_instance);
}
else
{
// LOGMSG_ERR("Send fail! instance: %d\n", m_instance);
}
count++;
usleep(1000000); // 1 sec
}
}
return NULL;
}
public:
int m_instance;
private:
std::atomic<bool> m_running;
MCastArbitrator MCArbi;
};
int main(int argc, char *argv[])
{
Sender *sender001 = new Sender(); sender001->InitComponent(1);
std::this_thread::sleep_for(std::chrono::seconds(1));
Sender *sender002 = new Sender(); sender002->InitComponent(2);
int count = 1;
int lastDie = 2;
while (true)
{
if (count % 5 == 0)
{
if (lastDie == 2)
{
sender001->ChangeStatusForTest();
lastDie = 1;
}
else
{
sender002->ChangeStatusForTest();
lastDie = 2;
}
count = 0;
}
count++;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}
Output
$ ./src/MCastArbitrator
20200502_183146_131 [MSG] MCastArbitrator:: SendArbitration: 70, 9136,Start thread
20200502_183146_132 [MSG] MCastArbitrator:: ReceiveArbitration: 106, 9137,Start thread
20200502_183146_632 [MSG] MCastArbitrator::SwitchStatus_LongTimeNoUpdate: 211, 9137,IN
20200502_183146_632 [MSG] MCastArbitrator:: PrintStatus: 174, 9137,Status updated Raise hand
20200502_183146_882 [MSG] MCastArbitrator:: PrintStatus: 174, 9137,Status updated Primary
20200502_183147_131 [MSG] Sender:: Main: 41, 9135,Send success! count: 1 instance: 1
20200502_183147_132 [MSG] MCastArbitrator:: SendArbitration: 70, 9139,Start thread
20200502_183147_132 [MSG] MCastArbitrator:: ReceiveArbitration: 106, 9140,Start thread
20200502_183147_132 [MSG] MCastArbitrator:: PrintStatus: 174, 9140,Status updated Secondary
20200502_183148_132 [MSG] Sender:: Main: 41, 9135,Send success! count: 2 instance: 1
20200502_183149_132 [MSG] Sender:: Main: 41, 9135,Send success! count: 3 instance: 1
20200502_183150_132 [MSG] Sender:: Main: 41, 9135,Send success! count: 4 instance: 1
20200502_183151_386 [MSG] MCastArbitrator::SwitchStatus_LongTimeNoUpdate: 211, 9140,IN
20200502_183151_386 [MSG] MCastArbitrator:: PrintStatus: 174, 9140,Status updated Raise hand
20200502_183151_386 [MSG] MCastArbitrator::SwitchStatus_LongTimeNoUpdate: 211, 9137,IN
20200502_183151_386 [MSG] MCastArbitrator:: PrintStatus: 174, 9137,Status updated Raise hand
20200502_183151_634 [MSG] MCastArbitrator:: PrintStatus: 174, 9137,Status updated Secondary
20200502_183151_634 [MSG] MCastArbitrator:: PrintStatus: 174, 9140,Status updated Primary
20200502_183152_132 [MSG] Sender:: Main: 41, 9138,Send success! count: 5 instance: 2
20200502_183153_132 [MSG] Sender:: Main: 41, 9138,Send success! count: 6 instance: 2
From the above output example, you can see that the first primary server is instance 1. After a while, we turn off instance 1 and then instance 2 comes up.