Skip to content

Instantly share code, notes, and snippets.

@dksmiffs
Last active June 23, 2022 09:20
Show Gist options
  • Save dksmiffs/d67afe6bda973d67752ae63dc49a7310 to your computer and use it in GitHub Desktop.
Save dksmiffs/d67afe6bda973d67752ae63dc49a7310 to your computer and use it in GitHub Desktop.
Linux C++ UDP multicast example, guidance here: https://www.tenouk.com/Module41c.html
// Guidance: https://www.tenouk.com/Module41c.html
#include <arpa/inet.h>
#include <array>
#include <iostream>
#include <netinet/in.h>
#include "udpSock.hpp"
#include "zz_diagnose.hpp"
int main()
{
UdpSock sock;
diagnose(sock.isGood(), "Opening datagram socket for receive");
{
// enable SO_REUSEADDR to allow multiple instances of this application to
// receive copies of the multicast datagrams.
int reuse = 1;
diagnose(setsockopt(sock(), SOL_SOCKET, SO_REUSEADDR, (char*)&reuse,
sizeof(reuse)) >= 0, "Setting SO_REUSEADDR");
}
// Bind to the proper port number with the IP address specified as INADDR_ANY
sockaddr_in localSock = {}; // initialize to all zeroes
localSock.sin_family = AF_INET;
localSock.sin_port = htons(4321);
localSock.sin_addr.s_addr = INADDR_ANY;
// Note from manpage that bind returns 0 on success
diagnose(!bind(sock(), (sockaddr*)&localSock, sizeof(localSock)),
"Binding datagram socket");
// Join the multicast group on the local interface. Note that this
// IP_ADD_MEMBERSHIP option must be called for each local interface over
// which the multicast datagrams are to be received.
ip_mreq group = {}; // initialize to all zeroes
group.imr_multiaddr.s_addr = inet_addr("226.1.1.1");
group.imr_interface.s_addr = inet_addr("127.0.0.1");
diagnose(setsockopt(sock(), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&group,
sizeof(group)) >= 0, "Adding multicast group");
// Read from the socket
std::array<char, 1024> arr;
arr.fill(0);
diagnose(read(sock(), arr.data(), arr.size()) >= 0,
"Reading datagram message");
std::cout << "Message from multicast sender: " << arr.data()
<< std::endl;
return 0;
}
// Guidance: www.tenouk.com/Module41c.html
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "udpSock.hpp"
#include "zz_diagnose.hpp"
int main()
{
UdpSock sock;
diagnose(sock.isGood(), "Opening datagram socket for send");
sockaddr_in groupSock = {}; // init to all zeroes
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr("226.1.1.1");
groupSock.sin_port = htons(4321);
in_addr localIface = {}; // init to all zeroes
localIface.s_addr = inet_addr("127.0.0.1");
diagnose(setsockopt(sock(), IPPROTO_IP, IP_MULTICAST_IF, (char*)&localIface,
sizeof(localIface)) >= 0, "Setting local interface");
const std::string databuf = "Multicast from C++";
diagnose(sendto(sock(), databuf.c_str(), databuf.length(), 0,
(sockaddr*)&groupSock, sizeof(groupSock)) >= 0,
"Sending datagram message");
return 0;
}
#include <sys/socket.h>
#include <unistd.h>
class UdpSock {
public:
UdpSock() {
m_sd = socket(AF_INET, SOCK_DGRAM, 0);
}
~UdpSock() {
// make sure the socket resource doesn't leak
if (isGood())
close(m_sd);
}
// Don't need the other default operations
UdpSock(const UdpSock&) = delete;
UdpSock& operator=(const UdpSock&) = delete;
UdpSock(UdpSock&&) = delete;
UdpSock& operator=(UdpSock&&) = delete;
int operator()() const {
return m_sd;
}
bool isGood() const {
return m_sd >= 0;
}
private:
int m_sd = -1;
};
// unusual file name is a hack to force GitHub Gist not to put this file at the top
#include <iostream>
#include <stdlib.h>
#include <string>
void diagnose(bool isGood, const std::string& action)
{
if (isGood)
std::cout << action.c_str() << " OK" << std::endl;
else
{
std::cerr << action.c_str() << " error" << std::endl;
exit(1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment