Как получить оставшийся размер буфера именованного канала (FIFO) в Linux

В моем приложении я использую Linux Named Pipe для потоковой передачи данных. Одно приложение (app1) записывает потоковые данные в этот FIFO, а другое приложение (app2) читает из него.

Когда размер FIFO заполнен, частичная запись будет записана в FIFO из app1, так как размер буфера канала (4096 байт) заполнен. При этом записи сливаются с какой-то другой записью. Итак, I want to know what is the remaining size in pipe buffer, прежде чем писать запись. При этом я могу сравнить текущий размер записи с оставшимся размером в буфере конвейера. Если размер записи больше, то App1 будет ждать и записывать полную запись всякий раз, когда канал освобождается, поскольку App2 будет непрерывно читать. Я пытался использовать это, но бесполезно:

fcntl(fd, F_GETPIPE_SZ );

Также есть ли способ проверить размер буфера этого оставшегося канала с помощью C или C++?


person Dkr    schedule 07.12.2018    source источник
comment
Краткий ответ: нет.   -  person Sam Varshavchik    schedule 07.12.2018
comment
Я не думаю, что это хороший дизайн. Вместо этого просто напишите все, что можно написать. Почему вы хотите написать только полное сообщение?   -  person SergeyA    schedule 07.12.2018
comment
@SergeyA: В противном случае он удаляет некоторые записи, и когда в какой-либо трубе есть место, он добавляет другие записи. поэтому он генерирует записи об ошибках.   -  person Dkr    schedule 07.12.2018
comment
Затем исправьте свою логику, чтобы она правильно обрабатывала значение, возвращаемое функцией write(), и не удаляла записи. Это очень распространенная, простая ситуация, которая постоянно обрабатывается путем правильного использования того, что возвращает функция write(), а затем обеспечения того, чтобы ненаписанная часть предыдущей записи была записана до следующей.   -  person Sam Varshavchik    schedule 07.12.2018
comment
@Dave, вам нужно проверить код возврата при записи, и если запись не была записана полностью, перезапишите оставшееся. Ваш код будет блокироваться до тех пор, пока не будет доступно больше места.   -  person SergeyA    schedule 07.12.2018
comment
@SamVarshavchik: опция изменения логики есть, но я хотел знать, есть ли способ найти оставшийся размер буфера, чтобы я мог проверить размер записи и свободное место в буфере перед записью.   -  person Dkr    schedule 07.12.2018
comment
Первый комментарий в этом вопросе уже сказал вам, есть ли способ. Тот ответ все тот же: нет, не существует. Я поддерживаю http://manpages.courier-mta.org и прочитал почти все справочные страницы. Я не припоминаю ничего подобного.   -  person Sam Varshavchik    schedule 07.12.2018
comment
Спасибо @SamVarshavchik   -  person Dkr    schedule 07.12.2018
comment
@SamVarshavchik, но это неправильно. Есть способ, по крайней мере, на некоторых версиях Linux. Я заканчиваю ответ.   -  person SergeyA    schedule 07.12.2018
comment
Использование FIONREAD не будет надежно работать при определении того, будет ли ваша предполагаемая запись успешной, по ряду причин.   -  person Sam Varshavchik    schedule 08.12.2018


Ответы (1)


Хотя я категорически не одобряю такой подход, есть способ добиться желаемой функциональности, по крайней мере, в некоторых версиях Linux. Для этого нужно использовать ioctl с командой FIONREAD, чтобы получить размер непрочитанных данных внутри канала. Соответствующая команда доступна не во всех Linux, но в моем она есть.

Следующий небольшой фрагмент кода показывает, как этот метод можно применить на практике. Пожалуйста, не думайте об этом много, это только для иллюстрации.

#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include <iostream>

int main() {
    const size_t buf_sz = 4096;
    int fd[2];
    pipe(fd);

    int cap = fcntl(fd[0], F_GETPIPE_SZ);
    std::cout << "Pipe capacity: " << cap << "\n";
    int sz = 0;
    while (((cap - sz) >= buf_sz)) {

        char buf[buf_sz];
        write(fd[1], buf, sizeof(buf));
        ioctl(fd[1], FIONREAD, &sz);
        std::cout << "Avaialble to write: " << cap - sz << "\n";
    }
    std::cout << "No more room in the pipe.\n";
    char buf[buf_sz];
    read(fd[0], buf, buf_sz);
    ioctl(fd[1], FIONREAD, &sz);
    std::cout << "Available now: " << cap - sz << "\n";
}

На моей машине он выдает следующий вывод: saristov@saristovlinux:~$ g++ test_pipe.cpp && ./a.out

Pipe capacity: 65536
Avaialble to write: 61440
Avaialble to write: 57344
Avaialble to write: 53248
Avaialble to write: 49152
Avaialble to write: 45056
Avaialble to write: 40960
Avaialble to write: 36864
Avaialble to write: 32768
Avaialble to write: 28672
Avaialble to write: 24576
Avaialble to write: 20480
Avaialble to write: 16384
Avaialble to write: 12288
Avaialble to write: 8192
Avaialble to write: 4096
Avaialble to write: 0

No more room in the pipe.
Available now: 4096
person SergeyA    schedule 07.12.2018