Skip to content

Instantly share code, notes, and snippets.

@hostilefork
Last active May 22, 2025 04:43
Show Gist options
  • Save hostilefork/f7cae3dc33e7416f2dd25a402857b6c6 to your computer and use it in GitHub Desktop.
Save hostilefork/f7cae3dc33e7416f2dd25a402857b6c6 to your computer and use it in GitHub Desktop.
Simple listener and sender for UDP multicast
//
// Simple listener.c program for UDP multicast
//
// Adapted from:
// http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/example.html
//
// Changes:
// * Compiles for Windows as well as Linux
// * Takes the port and group on the command line
//
#ifdef _WIN32
#include <Winsock2.h> // before Windows.h, else Winsock 1 conflict
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast
#include <Windows.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define MSGBUFSIZE 256
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("Command line args should be multicast group and port\n");
printf("(e.g. for SSDP, `listener 239.255.255.250 1900`)\n");
return 1;
}
char* group = argv[1]; // e.g. 239.255.255.250 for SSDP
int port = atoi(argv[2]); // 0 if error, which is an invalid port
#ifdef _WIN32
//
// Initialize Windows Socket API with given VERSION.
//
WSADATA wsaData;
if (WSAStartup(0x0101, &wsaData)) {
perror("WSAStartup");
return 1;
}
#endif
// create what looks like an ordinary UDP socket
//
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
perror("socket");
return 1;
}
// allow multiple sockets to use the same PORT number
//
u_int yes = 1;
if (
setsockopt(
fd, SOL_SOCKET, SO_REUSEADDR, (char*) &yes, sizeof(yes)
) < 0
){
perror("Reusing ADDR failed");
return 1;
}
// set up destination address
//
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY); // differs from sender
addr.sin_port = htons(port);
// bind to receive address
//
if (bind(fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
perror("bind");
return 1;
}
// use setsockopt() to request that the kernel join a multicast group
//
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (
setsockopt(
fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &mreq, sizeof(mreq)
) < 0
){
perror("setsockopt");
return 1;
}
// now just enter a read-print loop
//
while (1) {
char msgbuf[MSGBUFSIZE];
int addrlen = sizeof(addr);
int nbytes = recvfrom(
fd,
msgbuf,
MSGBUFSIZE,
0,
(struct sockaddr *) &addr,
&addrlen
);
if (nbytes < 0) {
perror("recvfrom");
return 1;
}
msgbuf[nbytes] = '\0';
puts(msgbuf);
}
#ifdef _WIN32
//
// Program never actually gets here due to infinite loop that has to be
// canceled, but since people on the internet wind up using examples
// they find at random in their own code it's good to show what shutting
// down cleanly would look like.
//
WSACleanup();
#endif
return 0;
}
//
// Simple sender.c program for UDP
//
// Adapted from:
// http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/example.html
//
// Changes:
// * Compiles for Windows as well as Linux
// * Takes the port and group on the command line
//
// Note that what this program does should be equivalent to NETCAT:
//
// echo "Hello World" | nc -u 239.255.255.250 1900
#ifdef _WIN32
#include <Winsock2.h> // before Windows.h, else Winsock 1 conflict
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast
#include <Windows.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h> // for sleep()
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("Command line args should be multicast group and port\n");
printf("(e.g. for SSDP, `sender 239.255.255.250 1900`)\n");
return 1;
}
char* group = argv[1]; // e.g. 239.255.255.250 for SSDP
int port = atoi(argv[2]); // 0 if error, which is an invalid port
// !!! If test requires, make these configurable via args
//
const int delay_secs = 1;
const char *message = "Hello, World!";
#ifdef _WIN32
//
// Initialize Windows Socket API with given VERSION.
//
WSADATA wsaData;
if (WSAStartup(0x0101, &wsaData)) {
perror("WSAStartup");
return 1;
}
#endif
// create what looks like an ordinary UDP socket
//
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
perror("socket");
return 1;
}
// set up destination address
//
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(group);
addr.sin_port = htons(port);
// now just sendto() our destination!
//
while (1) {
char ch = 0;
int nbytes = sendto(
fd,
message,
strlen(message),
0,
(struct sockaddr*) &addr,
sizeof(addr)
);
if (nbytes < 0) {
perror("sendto");
return 1;
}
#ifdef _WIN32
Sleep(delay_secs * 1000); // Windows Sleep is milliseconds
#else
sleep(delay_secs); // Unix sleep is seconds
#endif
}
#ifdef _WIN32
//
// Program never actually gets here due to infinite loop that has to be
// canceled, but since people on the internet wind up using examples
// they find at random in their own code it's good to show what shutting
// down cleanly would look like.
//
WSACleanup();
#endif
return 0;
}
@fabiensanglard
Copy link

I am not sure this code work reliably on multi-homed workstation. To send multicast UDP you need to send on all interfaces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment