2016-04-23 4 views
0

Я пытаюсь написать две последовательные строки. Проблема в том, что читатель продолжает приветствовать EAGAIN при использовании O_NONBLOCK на считывателе.Чтение двух последовательных записей из FIFO с использованием select() и O_NONBLOCK

Любые идеи, почему это не работает при использовании O_NONBLOCK, не должно select() заботиться о блоке?

reader.c

#include <fcntl.h> 
#include <stdlib.h> 
#include <stdint.h> 
#include <string.h> 

int main() { 
    int fd; 
    char * myfifo = "/tmp/myfifo"; 

    mkfifo(myfifo, 0666); 
    fd = open(myfifo, O_RDWR | O_NONBLOCK); 

    write(fd, "12345678", strlen("12345678")); 
    write(fd, "HelloWorld", strlen("HelloWorld")); 
    close(fd); 

    return 0; 
} 

writer.c

#include <fcntl.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <errno.h> 
#include <stdint.h> 

char buf[BUFSIZ] = { 0 }, buf2[BUFSIZ] = { 0 }; 
int read1 = 0, read2 = 0; 

int main() { 
    int fd = 0, a = 0, b = 0 ; 
    char *myfifo= "/tmp/myfifo"; 

    mkfifo(myfifo, 0666); 
    fd_set set; 

    if ((fd = open(myfifo, O_RDWR | O_NONBLOCK)) < 0) 
     exit(1); 

    while (1) { 
     FD_ZERO(&set); 
     FD_SET(fd, &set); 

     if ((select(fd+1, &set, NULL, NULL, NULL)) < 1) 
      exit(1); 

     if (FD_ISSET(fd, &set)) { 
      int total = 0; 

      if ((total = read(fd, buf + read1, sizeof(uint32_t) * 2) - read1) <= 0) { 
       fprintf(stderr, "%s\n", strerror(errno)); 
       continue; 
      } 
      read1 += total; 

      if ((total = read(fd, buf2 + read2, BUFSIZ - read2)) <= 0) { 
       fprintf(stderr, "%s\n", strerror(errno)); 
       continue; 
      } 
      read2 += total; 

      fprintf(stderr, "%s %d, %d, %s\n", buf, a, b, buf2); 
      memset(buf, 0, BUFSIZ); 
      memset(buf2, 0, BUFSIZ); 
      read1 = read2 = 0; 
     } 
    } 

    return 0; 
} 
+0

На странице Linux для «open» говорится об использовании O_RDWR на fifo: «O_RDWR Open для чтения и записи. Результат не определен, если этот флаг применяется к FIFO». – TonyB

+0

В Linux это нормально, см. Справочную страницу для 'fifo': под Linux открытие FIFO для чтения и записи будет успешным как в режиме блокировки, так и в режиме неблокирования. POSIX оставляет это поведение неопределенным. – fluter

ответ

0

Вы звоните read на дескриптором дважды в цикле, то возможно, что первый read читать данные доступный, а второй read не удастся с EAGAIN. Перед выполнением любых read вы должны проверить готовность с помощью select, а не только первую. Поскольку fifos - это потоки, это означает, что вы должны поддерживать собственную границу разных частей данных.

char buf[BUFSIZ]; 
if (FD_ISSET(fd, &set)) { 
    int total = 0; 
    int off = 0; 
    total = read(fd, buf, sizeof buf); 
    if (total <= 0) { 
      fprintf(stderr, "%s\n", strerror(errno)); 
      continue; 
    } 
    // retrieve the data based on how many bytes you have read 
    if (total >= sizeof(uint32_t) * 2) { 
     ... 
    } 
} 

Кроме того, рекомендуется открыть с O_RDONLY для чтения конца и O_WRONLY для написания конца ФИФО.

+0

Спасибо. Насколько я понимаю, я должен уметь читать «n» количество байтов на первом чтении, а число «n» на втором - читать? Из вашего примера, кажется, я должен читать весь размер буфера в одном чтении? –

+0

Кроме того, я считаю, что 'select()' не перестает быть «активным», если используется 'O_RDONLY' из-за' EOF', поэтому я должен использовать 'O_RDWR'. –

+0

@PeteDarrow Но не гарантировано, что вы можете прочитать n байтов при первом чтении, вы можете быть прочитаны меньше этого. Как я уже сказал, в потоках нет границ, то, что вы пишете в блоке, не обязательно читается как один блок. – fluter