I asked ChatGPT to write a simple C++ socket program to listen and and it didn’t work at first but after a few pointed questions and some scolding I was able to receive the Heartbeat in the c++ program.
#include <iostream>
#include <cstring>
#include <iomanip>
#include <algorithm>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <unistd.h>
void printBufferAsHex(const char* buffer, size_t bufferSize) {
size_t counter = 0;
size_t const width = 32;
size_t const width_2 = width / 2;
for (size_t i = 0; i < bufferSize; ++i) {
bool spacer = (counter > 0) and ((counter % width_2) == 0);
bool newline = (counter > 0) and ((counter % width) == 0);
printf("%s%s %02hhx", (spacer ? " " : ""), (newline ? "\r\n" : ""), buffer[i]);
counter++;
}
// If the last line didn't reach width bytes, add a newline
if (counter != 0) {
printf("\r\n");
}
}
int main(int argc, char* argv[]) {
if (argc < 4) {
std::cerr << "Usage: " << argv[0] << " <interface_address> <multicast_address> <port>" << std::endl;
return 1;
}
const char* interfaceAddress = argv[1];
const char* multicastAddress = argv[2];
const int port = std::stoi(argv[3]);
// Create a socket
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
std::cerr << "Failed to create socket." << std::endl;
return 1;
}
// Set SO_REUSEPORT option
int reuseAddr = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)) == -1) {
std::cerr << "Failed to set SO_REUSEADDR option." << std::endl;
close(sock);
return 1;
}
// Set SO_REUSEPORT option
int reusePort = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &reusePort, sizeof(reusePort)) == -1) {
std::cerr << "Failed to set SO_REUSEPORT option." << std::endl;
close(sock);
return 1;
}
// Bind the socket to the specified interface address and port
struct sockaddr_in interfaceAddr;
std::memset(&interfaceAddr, 0, sizeof(interfaceAddr));
interfaceAddr.sin_family = AF_INET;
interfaceAddr.sin_addr.s_addr = inet_addr(interfaceAddress);
interfaceAddr.sin_port = htons(port);
// Set IP_MULTICAST_IF option
if (inet_pton(AF_INET, interfaceAddress, &interfaceAddr) != 1) {
std::cerr << "Failed to convert interface address." << std::endl;
close(sock);
return 1;
}
// Set socket options for multicast
int ttl = 1;
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
std::cerr << "Failed to set TTL." << std::endl;
close(sock);
return 1;
}
// Set up the multicast group address and port
struct sockaddr_in multicastAddr;
std::memset(&multicastAddr, 0, sizeof(multicastAddr));
multicastAddr.sin_family = AF_INET;
multicastAddr.sin_addr.s_addr = inet_addr(multicastAddress);
multicastAddr.sin_port = htons(port);
if (bind(sock, (struct sockaddr*)&multicastAddr, sizeof(multicastAddr)) < 0) {
std::cerr << "Failed to bind socket to multicast address." << std::endl;
close(sock);
return 1;
}
// Join the multicast group
struct ip_mreq multicastRequest;
multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastAddress);
multicastRequest.imr_interface.s_addr = inet_addr(interfaceAddress);
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&multicastRequest, sizeof(multicastRequest)) < 0) {
std::cerr << "Failed to join multicast group." << std::endl;
close(sock);
return 1;
}
std::cout << "Socket successfully opened on multicast address " << multicastAddress << " and port " << port << " with interface address " << interfaceAddress << "." << std::endl;
char buffer[1500];
struct sockaddr_in senderAddr;
socklen_t senderAddrLen = sizeof(senderAddr);
while (true) {
// Receive a UDP datagram
ssize_t numBytes = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&senderAddr, &senderAddrLen);
if (numBytes < 0) {
std::cerr << "Failed to receive data." << std::endl;
close(sock);
return 1;
}
buffer[numBytes] = '\0';
// Dump the contents of the received message
std::cout << "Received " << numBytes << " bytes from " << inet_ntoa(senderAddr.sin_addr) << ":" << ntohs(senderAddr.sin_port) << std::endl;
std::cout << "Message: " << std::endl;
size_t len = (numBytes < sizeof(buffer)) ? numBytes : sizeof(buffer);
printBufferAsHex(buffer, len);
std::cout << "==========================================" << std::endl;
// Continue listening for more datagrams
}
// Cleanup and close the socket
close(sock);
return 0;
}
Compiling (i’m on Mac)
clang++ -std=c++14 -I/usr/include multicast.cpp -o multicast
Running:
./multicast 172.16.0.100 239.0.29.85 9382
I didn’t need to be sudo
to receive.