Можно ли использовать функцию `recvfrom` для проверки того, были ли какие-либо предыдущие данные отправлены в сокет? Или он должен активно прослушиваться?

#c #sockets #unix-socket

#c #сокеты #unix-socket

Вопрос:

У меня есть while(1) цикл, который используется recvfrom для получения данных, которые были отправлены в сокет домена из другого процесса (P2).

Цикл while должен выполнить 2 вещи: во-первых, прослушать входящие данные с P2, а во-вторых, запустить другую функцию checkVoltage() .

Итак, он выполняет что-то вроде этого:

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

Моя проблема заключается в следующем: listenOnSocket() функция использует recvfrom функцию для проверки ввода от другого процесса. Он тратит 100 секунд на прослушивание, затем истекает время ожидания и переходит к запуску checkVoltage() функции. Таким образом, он тратит около 99% времени на listenOnSocket() функцию. Моя проблема в том, что если P2 отправляет информацию в сокет во checkVoltage() время выполнения функции, то это приведет к ошибке с указанием: sending datagram message: No such file or directory .

Есть ли способ проверить этот цикл на наличие любых данных, которые были отправлены в сокет ранее? Таким образом, если P2 отправляет данные во checkVoltage() время выполнения функции, это не приведет к ошибке.

Спасибо.

Редактировать:

Таким listenOnSocket() образом, функция создает сокет с именем FireControl , когда я запускаю P1 (программу, которая получает данные от P2) FireControl , файл исчезает на долю секунды, а затем появляется снова. Если P2 отправляет данные в P1 в течение этого короткого периода, это приводит к ошибке, упомянутой выше.

Итак, я предполагаю, что это означает, что я должен отделить создание сокета от recvfrom функции, потому что короткий период, в течение которого создается новый сокет, не существует — если это имеет смысл.

Я дурак, я должен был разделить их в первую очередь!

EDIT2: вот 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 *) amp;name, sizeof(struct sockaddr_un))) 
    {
        perror("binding name to datagram socketn");
        payload = nullPayload;
    }

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

    unlink(NAME);   
    return payload;
}
  

и вот цикл, который его вызывает:

 while (1)
    {
        buffer = getADCValue();

        checkVoltage();

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

Комментарии:

1. «отправлено в доменный сокет» -> учитывая тег, правильно ли я предполагаю, что вы имеете в виду доменный сокет UNIX?

2. Кроме того, вы уверены, что ваш сокет вообще работает? AFAIK, вам не нужно зацикливаться recvfrom на send sendto вызове / из P2 для успешного завершения, сообщения должны быть поставлены в очередь при условии, что сокет существует.

3. @zneak да, это доменный сокет unix (работает на Raspbian). Сокеты определенно работают, в другом разделе кода я запускаю listenOnSocket без какого-либо тайм-аута, и программа работает с recvfrom функцией, пока она ожидает ввода.

4. Теперь добавим немного больше информации к вопросу

5. Это источник вашей проблемы. listenOnsocket() всегда удаляет и создает новый сокет. Вы должны создать сокет только один раз при вводе кода сервера, а затем выполнить цикл recvfrom() . Этот цикл создания и удаления уничтожит все, что находится в очереди в сокете.

Ответ №1:

Я предполагаю, что это означает, что я должен отделить создание сокета от функции recvfrom, потому что короткий период, в течение которого создается новый сокет, не существует

Это правильно. Если вы каждый раз открываете и закрываете сокет в своем listenOnSocket() сокете, (а) вы потеряете все дейтаграммы, которые попали в очередь, которые вы не читали, и (б) отправка при закрытом сокете завершится ошибкой … конечно. Им нечего отправлять.

Ответ №2:

Как только вы свяжете сокет, дейтаграммы будут накапливаться в буфере и могут быть прочитаны позже с помощью recvfrom. Тем не менее, если буфер переполняется, сообщения могут быть отброшены.