ФАЙЛ* чтение с таймаутом

#c #stream #timeout #libc

#c #поток #тайм-аут #libc

Вопрос:

Я создаю коммуникационную библиотеку, которая принимает поток файлов и использует его для чтения и записи. Протокол определяет тайм-ауты, поэтому я хочу их использовать.

Я использую fread(3) и fwrite(3) . Я слышал о select(2) , и это то, что я ищу, за исключением того, что он использует файловые дескрипторы, а не файловые потоки libc — я хочу поддерживать пользовательские файловые потоки, созданные с fopencookie(3) помощью, полезные для тестов и других вещей, тоже. Я попытался настроить SIGALRM с alarm(2) помощью, чтобы получить сообщение об EINTR ошибке fread(3) (настройка обратного вызова для SIGALRM использования signal(2) ), но это не остановит fopen вызов, как ожидалось…

Заранее спасибо за любое решение.

РЕДАКТИРОВАТЬ: похоже, это работает.. но только один раз. При втором вызове это не … Oo

 /**
 *  sigalrm_handler:
 *  Shut up SIGALRM.
 *
 *  @arg    code        signal code (always SIGALRM)
 */

static __thread jmp_buf env_alrm;
static void sigalrm_handler(int signo)
{
    (void)signo;
    /* restore env */
    longjmp(env_alrm, 5);
}

/**
 *  _p7_fread:
 *  Read file with timeout.
 *
 *  @arg    ptr         the buffer pointer
 *  @arg    size        the size of an item
 *  @arg    nitems      the number of items in the buffer
 *  @arg    stream      the stream
 *  @arg    timeout     the timeout (seconds)
 *  @return             the number of read bytes
 */

size_t _p7_fread(void *ptr, size_t size, size_t nitems, FILE *stream,
    int timeout)
{
    size_t read_count = 0;

    /* set long jump */
    int val = setjmp(env_alrm);
    if (!val) {
    /* setup signal handler */
        if (signal(SIGALRM, amp;sigalrm_handler) == SIG_ERR)
            return (0);

        /* setup alarm */
        alarm(timeout);

        /* read */
        read_count = fread(ptr, size, nitems, stream);
    } else
        errno = EINTR;

    /* unset signal handler and alarm */
    signal(SIGALRM, NULL);
    alarm(0);

    /* return */
    return (read_count);
}
  

Еще раз, спасибо за любую помощь ^^

Ответ №1:

функция: fdopen() получит указатели на файлы из файловых дескрипторов.

Затем вы можете использовать функцию: select() с указателями файлов, которые были возвращены из fdopen() .

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

1. Но как насчет внутренних буферов в структуре FILE * ? А как насчет файловых потоков, у которых нет файлового дескриптора (я имею в виду созданные с fopencookie помощью)?

2. это из: <> «Функция fdopen() связывает поток с существующим файловым дескриптором fd. Режим потока (одно из значений «r», «r «, «w», «w «, «a», «a «) должен быть совместим с режимом файлового дескриптора. Для индикатора положения файла нового потока устанавливается значение, принадлежащее fd, а индикаторы ошибки и конца файла очищаются. Режимы «w» или «w » не вызывают усечения файла. Файловый дескриптор не дублируется и будет закрыт, когда поток, созданный fdopen(), будет закрыт. Результат применения fdopen() к объекту с общей памятью не определен «.

3. Итак, я попробовал select и fileno . Но факт fileno в том, что возвращает -1 для пользовательского потока, созданного с fopencookie помощью, поэтому я не могу использовать select его. И если я хочу протестировать тайм-ауты с помощью пользовательских файловых потоков… так что это не сработает для меня. :/

4. @Cakeisalie5, чего именно ты пытаешься достичь? Понимаете ли вы, что «cookie» — это объект памяти, а не реальный поток ввода-вывода, поэтому какая-то внешняя сила, изменяющая эту память, не вызовет событие, которое будет распознано, например select() ?

5. Я понял это, я использую пользовательские потоки файлов для тестирования. Но именно поэтому я не могу использовать select для своего случая (поскольку я также хочу проверять тайм-ауты в пользовательских файловых потоках)… итак, я ищу более общий способ сделать fopen / fwrite timeout (/cause EINTR , который я не нашел, как вызвать даже с alarm ).