Search code examples
csocketsunix-socket

Can the `recvfrom` function be used to check whether there have been any previous data sent to a socket? Or does it need to be actively listening?


I have a while(1) loop that uses recvfrom to get data that has been sent to a domain socket from another process (P2).

The while loop needs to do 2 things, firstly listen for incoming data from P2, and secondly run another function checkVoltage().

So it runs a little something like this:

while(true)
{
    listenOnSocket() /*listens for 100 u seconds*/
    checkVoltage();
}

My issue is this: the listenOnSocket() function uses the recvfrom function to check for an input from another process. It spends 100usecs listening, then times out and proceeds to run the checkVoltage() function. So it spends like 99% of the time in the listenOnSocket() function. My issue is that if P2 sends information to the socket during the checkVoltage() function, then it will result in an error, stating: sending datagram message: No such file or directory.

Is there a way to have this loop check for any data that has been sent to the socket previously? That way if P2 sends data during the checkVoltage() function, it will not result in an error.

Thanks.

EDIT:

So the listenOnSocket() function creates a socket with the name FireControl when I run P1 (the program that receives data from P2) the FireControl file vanishes for a split second then reappears. If P2 sends data to P1 during this short period, it results in the error mentioned up top.

So I guess this means I should separate the creation of the socket from the recvfrom function, because the short period where the new socket is created it does not exist - if that makes sense.

I'm a dope, I should've separated them in the first place!

EDIT2: Here is listenOnSocket():

command listenOnSocket(int timeout, float utimeout) /*Returns null payload when no input is detected*/
{
    command payload;
    int sock;
    socklen_t* length;
    struct sockaddr_un name;
    char buf[1024];

    struct timeval tv;
    tv.tv_sec = timeout;
    tv.tv_usec = utimeout;

    /* Create socket from which to read. */
    sock = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (sock < 0) 
    {
        perror("opening datagram socket");
        payload = nullPayload;
    }

    /* Create name. */
    name.sun_family = AF_UNIX;
    strcpy(name.sun_path, NAME);

    unlink(name.sun_path);

    /* Bind the UNIX domain address to the created socket */
    if (bind(sock, (struct sockaddr *) &name, sizeof(struct sockaddr_un))) 
    {
        perror("binding name to datagram socket\n");
        payload = nullPayload;
    }

    /*Socket has been created at NAME*/
    if (timeout != 0 || utimeout != 0)
    {
        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
    }
    else
    {
        tv.tv_sec = 0;
        tv.tv_usec = 0;
        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
    }
    /* Read from the socket */
    if (recvfrom(sock, &payload, sizeof(command), 0, (struct sockaddr *)&name, &length) < 0) /*Less than zero results from a timeout*/
    {
        payload = nullPayload;
    }

    unlink(NAME);   
    return payload;
}

and here is the loop that calls it:

while (1)
    {
        buffer = getADCValue();

        checkVoltage();

        temp = listenOnSocket(0, 100); /*Look for a new command*/
        doStuffWithTempIfItHasChanged();
        }
    }

Solution

  • Once you've bound the socket, the datagrams will accumulate in a buffer and can be read later using recvfrom. That said, if the buffer overflows, messages may be discarded.