Skip to content

Instantly share code, notes, and snippets.

@hostilefork
Last active April 16, 2024 15:32
Show Gist options
  • Star 67 You must be signed in to star a gist
  • Fork 18 You must be signed in to fork a gist
  • 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;
}
@tianbengdilie
Copy link

sender in this demo send to the same port this listener, it can be sent to different port. And listener receives message with same group ip

@frenchjam
Copy link

Thanks for this example. Can this be used to have a single sender and multiple receivers, all on the same machine/interface?
I am going to try it to find out, but if someone is listening, please let me know if this is possible.

@Ranner198
Copy link

LOL Love the message in LN 100 of sender.c

@iamfahad43
Copy link

is that really works?
after a day of setting it is still standing there and here is the sender output: " sendto: Success " but nothing at listener???

@Ranner198
Copy link

@iamfahad43 I used it two weeks ago and had no problems, check your routing is what I would recommend. You can try running the application as an admin or enabling the passthrough through your firewall port.

@Goldenkrew3000
Copy link

Thanks :) Couldn't figure out how to use UDP in C

@v-slava
Copy link

v-slava commented Feb 8, 2022

Due to binding to INADDR_ANY in listener here, the listener receives not only multicast traffic but also unicast from any IP.

@pawelsc2
Copy link

setsockopt: No error

@orivee
Copy link

orivee commented Jun 2, 2023

Thanks for this example. Can this be used to have a single sender and multiple receivers, all on the same machine/interface? I am going to try it to find out, but if someone is listening, please let me know if this is possible.

I test, It Works.

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