2016-04-23 14 views
0

Ich versuche, zwei aufeinanderfolgende Strings zu schreiben. Das Problem ist, dass der Leser immer EAGAIN begrüßt, wenn O_NONBLOCK auf dem Leser verwendet wird.Lesen von zwei aufeinanderfolgenden Schreibvorgängen aus einem FIFO mit select() und O_NONBLOCK

Irgendwelche Ideen, warum es nicht funktioniert, wenn Sie O_NONBLOCK verwenden, sollte select() nicht auf den Block achten?

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

Die Linux-Manpage für "open" sagt Folgendes über die Verwendung von O_RDWR auf einem FIFO: "O_RDWR Öffnen zum Lesen und Schreiben. Das Ergebnis ist nicht definiert, wenn dieses Flag auf einen FIFO angewendet wird." – TonyB

+0

Unter Linux ist es in Ordnung, siehe man Seite für 'fifo': Unter Linux wird das Öffnen eines FIFOs zum Lesen und Schreiben sowohl im blockenden als auch im nicht blockierenden Modus gelingen. POSIX lässt dieses Verhalten undefiniert. – fluter

Antwort

0

Sie rufen read auf der fd zweimal in der Schleife ist es möglich, dass die erste read die Daten gelesen verfügbar, und die zweite read wird mit EAGAIN fehlschlagen. Sie sollten die Bereitschaft mit Select testen, bevor Sie read ausführen, nicht nur die erste. Da es sich bei Fifos um Streams handelt, müssen Sie Ihre eigenen Grenzen verschiedener Datenbereiche beibehalten.

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) { 
     ... 
    } 
} 

Auch wird empfohlen, mit O_RDONLY für das Leseende zu öffnen und O_WRONLY für das Schreiben Ende des Fifo.

+0

Danke. Von dem, was ich verstehe, sollte ich in der Lage sein, "n" Menge von Bytes auf dem ersten gelesen zu werden, und "n" Betrag auf dem zweiten Lesen? Von Ihrem Beispiel, es scheint, dass ich die gesamte Größe des Puffers in einem lesen sollte? –

+0

Ich glaube auch 'select()' hört nicht auf aktiv zu sein, wenn 'O_RDONLY' wegen' EOF' verwendet wird, also muss ich 'O_RDWR' verwenden. –

+0

@PeteDarrow Aber es ist nicht garantiert, dass Sie beim ersten Lesen n Bytes lesen können, Sie könnten weniger als das gelesen werden. Wie gesagt, es gibt keine Grenzen in Streams, was Sie in einem Block schreiben, muss nicht unbedingt als ein Block gelesen werden. – fluter