Simple multicast receiver in c

2 minute read

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

Tags: ,

Categories:

Updated:

Leave a comment