2016-04-23 14 views
0

2つの連続した文字列を書き込もうとしています。問題は、リーダーにO_NONBLOCKを使用すると、EAGAINに対して挨拶を続けていることです。select()とO_NONBLOCKを使用してFIFOから2つの連続した書き込みを読み取る

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

"open"のLinux manページでは、fifoでO_RDWRを使用する場合、次のように記述しています。 "O_RDWR読み書き用にオープン。このフラグをFIFOに適用すると、結果は未定義です。 – TonyB

+0

Linuxの場合、 'fifo'のマニュアルページを参照してください。Linuxでは、読み込みと書き込みのためにFIFOを開くと、ブロックモードと非ブロックモードの両方で成功します。 POSIXはこの動作を未定義にしています。 – fluter

答えて

0

あなたがループ内で二回FDにreadを呼び出している、最初readがデータを読み取ることは可能です2番目のreadは、EAGAINで失敗します。 最初のものだけでなく、readを実行する前に、selectを使用して準備状況をテストする必要があります。 FIFOはストリームなので、つまり、データの異なる部分の境界を維持する必要があります。

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

また、FIFOの書き込み終了を読み終わりのためのO_RDONLY、およびO_WRONLYで開くことをお勧めします。

+0

ありがとうございます。私が理解していることから、最初の読み込みではn個のバイトを読み込み、2番目の読み込みではn個の読み込みができるはずです。あなたの例から、私は1つの読み取りでバッファの全体のサイズを読み取る必要がありますか? –

+0

また、 'EOF'のために' O_RDONLY'が使われている場合、 'select()'が 'active 'になることはなく、' O_RDWR'を使う必要があります。 –

+0

@PeteDarrowしかし、最初の読み込みでnバイトを読み出すことはできませんが、それよりも読みにくいかもしれません。私が言ったように、川には境界がありません。あなたがブロックで書くものは、必ずしも1つのブロックとして読まれるわけではありません。 – fluter

関連する問題