На вход программе (через Unix Domain Socket или через stdin) приходит сообщение произвольной длины, после чего отправитель ожидает ответа.
Так как сообщение произвольной длины, не получается использовать read(length)
или recv(length)
— если длина сообщения окажется кратной length
, то случится взаимоблокировка (клиент ждёт ответа, сервер ждёт продолжения сообщения).
Решением было бы посмотреть, есть ли в буфере байты.
man ioctl
предлагает такое решение:
while ((ioctl(sock, I_NREAD, &num) >= 0) && num > 0)
/* дописать даные из буфера ввода в буфер в памяти */
, но это не работает для stdin
(ошибка ENOTTY
):
if ((ioctl(0, I_NREAD, &num) >= 0) && num > 0) /* ошибка ENOTTY */
Есть ли общий способ? Или для сокета и для stdin обязательно надо применять разные подходы (если так, то какие)?
EDIT: пример кода «клента» (на пхп):
$proc_handle = proc_open('./run', [['pipe', 'r'],['pipe', 'w']], $pipes);
foreach ($test_cases as $request => $response)
{
echo "Test: ".$request;
fwrite($pipes[0], $request);
fflush($pipes[0]);
echo "Answer: ".fgets($pipes[1]);
echo "\n";
}
EDIT: Пример решения: перевод stdin
в неблокирующий режим (подсказал u/Elyas, решение взято с https://stackoverflow.com/a/30548692):
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
static int counter = 0;
void updatecounter(void)
{
int n;
char buf[100];
while (1)
{
if ((n = read(0, buf, 100)) <= 0) break;
counter += n;
}
}
int main(void)
{
fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
while (1)
{
updatecounter();
printf("%d\n", counter);
sleep(2);
}
return 0;
}
EDIT: Пример решения: использование poll
(подсказал u/mittorn):
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
static int counter = 0;
void updatecounter(void)
{
char buf[100];
struct pollfd pollfds[1] = {0, POLLIN, 0};
while (1)
{
if (!poll(pollfds, 1, 0)) break;
counter += read(0, buf, 100);
}
}
int main(void)
{
while (1)
{
updatecounter();
printf("%d\n", counter);
sleep(2);
}
return 0;
}
EDIT: решение от u/kardapoltsev : указывать длину сообщения перед его началом
EDIT: оба решения проверены на сокетах.