Search code examples
csocketsudpbroadcastfifo

Data accumulates (FIFO?) in broadcast UDP socket


I have a device that sends me a stream of monitoring data (size of 58) every second, in broadcast. I'm reading this stream with a C program. My problem is if i don't read this stream for a few seconds, the next time i read it, i got much more datas that i needed, like if i had a FIFO that keeps filling during the time i'm not reading the stream.

I tried using different methods of reading, like using select, non-blocking socket ... always the same. Maybe there is just a detail that i miss ... Here is an example code :

#include <stdio.h>      /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), sendto(), and recvfrom() */
#include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */
#include <stdlib.h>     /* for atoi() and exit() */
#include <string.h>     /* for memset() */
#include <unistd.h>     /* for close() */

#define MAXRECVSTRING 58  /* Longest string to receive */


int main(int argc, char *argv[])
{
    int sock;                         /* Socket */
    struct sockaddr_in broadcastAddr; /* Broadcast Address */
    unsigned short broadcastPort;     /* Port */
    char recvString[MAXRECVSTRING+1]; /* Buffer for received string */
    int recvStringLen;                /* Length of received string */

    if (argc != 2)    /* Test for correct number of arguments */
    {
        fprintf(stderr,"Usage: %s <Broadcast Port>\n", argv[0]);
        exit(1);
    }

    broadcastPort = atoi(argv[1]);   /* First arg: broadcast port */

    /* Create a best-effort datagram socket using UDP */
    if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
        perror("socket() failed");

    /* Construct bind structure */
    memset(&broadcastAddr, 0, sizeof(broadcastAddr));   /* Zero out structure */
    broadcastAddr.sin_family = AF_INET;                 /* Internet address family */
    broadcastAddr.sin_addr.s_addr = htonl(INADDR_ANY);  /* Any incoming interface */
    broadcastAddr.sin_port = htons(broadcastPort);      /* Broadcast port */

    /* Bind to the broadcast port */
    if (bind(sock, (struct sockaddr *) &broadcastAddr, sizeof(broadcastAddr)) < 0)
        perror("bind() failed");

    /* Receive datagram from the server */
    int g=0;
    int time_to_sleep=10; 
    while(1)
    {
        if(g==10)
        {
            while(time_to_sleep)
            {
                printf("sleep for %d\n", time_to_sleep);
                time_to_sleep=sleep(time_to_sleep);
            }//after that my next read is 10 data stream of 58 in one !!
        }


        if ((recvStringLen = recvfrom(sock, recvString, MAXRECVSTRING, 0, NULL, 0)) < 0)
        {
             perror("recvfrom() failed");
        }
        //later will check the header but for now just the size is enough
        if (recvStringLen==58){ printf("Read okay bc Size = %d \n", recvStringLen); }


    }

    close(sock);
    exit(0);
}

So i will try to explain my problem : My equipment sends me UDP packets (size 58) every seconds that i keep reading continuously. After x time (g==10) i decide to sleep during 10seconds. During these 10seconds my equipment keeps sending UDP packets, but i don't read them and don't want to. At the 11th seconds, when i wake up i want to read my (g==10)+11th packets and not the 11th + the 10 i did not read during i slept. Unfortunately, when i read the 11th with a single recvfrom i get all the 10 previous one ...

I tried with and without an ethernet switch in case, but same problem. I must misunderstand something in socket ... can you help me ?

By the way, my code may be pure disaster, i'm a beginner. Do not hesitate to correct me !

Thank you !


Solution

  • I must misunderstand something in socket ... can you help me ?

    There are receive and send socket buffers in the kernel. The kernel receives datagrams for your listening socket and stores them in the kernel socket receive buffer. recvfrom call copies the oldest datagram from the kernel socket buffer into your user-space buffer. The fact that you do not call recvfrom doesn't mean the kernel stops receiving datagrams (you would need to close the socket for the kernel to stop receiving data).