Simple multicast receiver in c
A simple test program can be created for receiving multicast data. Socket buffer size of multicast is limited and udp data can be easily dropped. So it is highly recommended to read immediately from the socket buffer and put it in your receiving queue without any action in the business environment.
Receiving multicast data (mrecv.c)
#include <studio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/un.h>
#define BUF_SIZE 4096
int main (int argc, char *argv[])
{
// Local variables
int state;
ssize_t liRecvLen;
int liRtn;
int sock_fd;
int liMax;
int liPort;
char lsMsg[BUF_SIZE];
struct sockaddr_in sock_addr={0};
int socklen = sizeof(struct sockaddr_in);
fd_set ready, temps;
time_t ltime;
time(&time);
struct timeval to;
// Multicast variables
struct ip_mreq join_addr;
char multicast_ip[32];
char interface_ip[32];
// Initialize
memset(lsMsg, 0x20, sizeof(lsMsg));
memset(&sock_addr, 0x00, sizeof(sock_addr));
if (argc != 4) {
printf("Usage : %s <multicast ip> <interface ip> <listen port>\n", argv[0]);
return (-1);
}
strcpy(multicast_ip, argv[1]);
strcpy(interface_ip, argv[2]);
liPort = atoi(argv[3]);
// Create socket
sock_fd = socket(PF_INET, SOCK_DGRAM, 0);
if (xock_fd < 0) {
printf("Failed to create socket\n");
return (-1);
}
// Socket address
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//sock_addr.sin_addr.s_addr = inet_addr(interface_ip);
sock_addr.sin_port = htons(liPort);
// Binding
if (bind(sock_fd, (stuct sockaddr *)&sock_addr, sizeof(struct sockaddr_in)) < 0)
{
printf("UdpsockFd bind error(%d:%s):Port[%d]", errno, strerror(errno), liPort);
close(sock_fd);
return (-1);
}
// Multicast option : membership
join_addr.imr_multiaddr.s_addr = inet_addr(multicast_ip);
//join_addr.imr_multiaddr.s_addr = htonl(INADDR_ANY);
state = setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&join_addr, sizeof(join_addr));
if (state) {
printf("setsockopt error(%d)\n", state);
return (-1);
}
// Set FD_SET
if (sock_fd > 0) {
FD_SET(sock_fd, &ready);
if (sock_fd > liMax) {
liMax = sock_fd;
}
} else {
printf("sock_fd error\n");
return (-1);
}
// Loop
while(1)
{
temps = ready;
to.tv_sec = 10L;
to.tv_usec = 0L;
liRtn = select(liMax+1), &temps, (fd_set *)0, (fd_set *)0, &to);
if (liRtn == 0) { // select timeout
continue;
}
else if(liRtn < 0) { // select error
printf("[%s:%d]select(%d) Max=[%d] errno=[%d]%s\n", __FILE__, __LINE__, liRtn, liMax, errno, strerror(errno));
break;
}
if (sock_fd > 0 && FD_ISSET(xock_fd, &temps)) {
liRtn--;
memset(lsMsg, 0x00, BUF_SIZE);
liRecvLen = recvfrom(sock_fd, lsMsg, (size_t)BUF_SIZE, 0, (struct sockaddr*)&sock_addr, &socklen);
printf("RECV:[%d]%s\n", liRecvLen, lsMsg);
}
} // End of while
}
The below sysctl command prints the max OS socket receive buffer size for all types of connections.
$ sudo sysctl net.core.rmem_max
net.core.rmem_max = 212992
$ sudo sysctl net.ipv4.udp_mem
net.ipv4.udp_mem = 181110 241480 362220
You can see how many packets have been dropped on your machine with netstat -suna.
$ netstat -suna
IcmpMsg:
InType3: 16
OutType3: 86
Udp:
113869 packets received
69 packets to unknown port received
0 packet receive errors
68746 packets sent
0 receive buffer errors
0 send buffer errors
IgnoredMulti: 13336
UdpLite:
IpExt:
InMcastPkts: 50909
OutMcastPkts: 3175
InBcastPkts: 13336
OutBcastPkts: 23
InOctets: 10052985219
OutOctets: 10132287243
InMcastOctets: 9626110
OutMcastOctets: 243454
InBcastOctets: 1511133
OutBcastOctets: 1031
InNoECTPkts: 54703380
Leave a comment