#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. Тем не менее, если буфер переполняется, сообщения могут быть отброшены.