2016-04-19 21 views
1

I read()のselect()を使ってクライアントとFIFOからread()を行うと同時に、select()はFIFOからのデータを認識させます。現時点では、データがFIFOに書き込まれると、selectはすべてのデータをクライアントに書き込みますが、 "ready-to-read"のように戻ります。したがって、次の読み取り値は-1errno == EAGAINに設定されます。それはfdmaxに達するまでこれを行います。しかし、それは大丈夫です。クライアントからサーバに接続されたクライアントのC

しかし、なぜ私はEAGAINを得続けますか?これを処理するにはより良い方法がありますか?またはこれは適切な方法ですか?

注:私はO_RDWR|O_NONBLOCKを渡しているので、FIFOだけでなくクライアントによってもデータが送信されるようにします。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 
#include <fcntl.h> 
#include <errno.h> 

#define PORT "9034" 
int main(void) { 
    fd_set master, read_fds; 
    int fdmax, listener, newfd, sbytes, yes=1, i, j, rv; 
    struct sockaddr_storage remoteaddr; // client address 
    socklen_t addrlen; 
    char buf[256] = {0}, remoteIP[INET6_ADDRSTRLEN]; 
    struct addrinfo hints, *ai; 

    FD_ZERO(&master); 
    FD_ZERO(&read_fds); 
    int fifo; 
    if ((mkfifo("/tmp/fifo", 0666)) < 0) 
     perror(strerror(errno)); 
    if ((fifo = open("/tmp/fifo", O_RDWR|O_NONBLOCK)) < 0) 
     perror(strerror(errno)); 

    // get us a socket and bind it 
    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; 
    rv = getaddrinfo(NULL, PORT, &hints, &ai); 
    listener = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 
    setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); 
    bind(listener, ai->ai_addr, ai->ai_addrlen); 
    freeaddrinfo(ai); 
    listen(listener, 10); 

    FD_SET (fifo, &master); 
    FD_SET(listener, &master); 
    fdmax = listener; 
    for (;;) { 
     read_fds = master; 
     if (select(fdmax + 1, &read_fds, NULL, NULL, NULL) == -1) exit(4); 

     for (i = 0; i <= fdmax; i++) { 
      if (FD_ISSET(i, &read_fds)) { 
       if (i == listener) { 
        addrlen = sizeof remoteaddr; 
        newfd = accept(listener, (struct sockaddr *) & remoteaddr, & addrlen); 
        FD_SET(newfd, & master); 
        if (newfd > fdmax) 
         fdmax = newfd; 
       } else if (i != fifo) { 
        recv(i, buf, sizeof buf, 0); 
       } 
      } 
      if (FD_ISSET(fifo, &read_fds)) { 
       sbytes = read (fifo, buf, sizeof (buf)); 
       if (sbytes == -1 && errno == EAGAIN) 
        continue; 
       for(j = 0; j <= fdmax; j++) { 
        // send to everyone! 
        if (FD_ISSET(j, &master)) { 
         if (j != listener && j != i && j != fifo) { 
          if (send(j, buf, sbytes, 0) == -1) { 
           perror("send"); 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
    return 0; 
} 
+0

'fdmax = listener;'は疑わしいです。実際にはどちらが大きいかを評価する必要があります。それぞれの 'recv()'の結果をチェックする必要があります。あなたはソケットケースでそれをやっていません。具体的には、ゼロになる可能性があります。つまり、ピアが切断されているため、ソケットを閉じて 'read_fds'と' master'からソケットを削除する必要があります。 – EJP

+0

ありがとうございます。簡単にするために、私は多くの小切手を取り除いた。私はそれを追加することを確認します。 –

+0

'fdmax'と同様に、助けがあれば、[this code of code](https://github.com/boazsegev/c-server-tools/blob/b27548898dea4b0e8fb42b439dd7f50d7c0e7073/src/lib-server)を見ることができます。 c#L1729-L1749)は、プロセスの最大ファイル制限をチェックします(OSのハード制限まで最大化しようとします)。 – Myst

答えて

1
for (i = 0; i <= fdmax; i++) { 

ここでは、read_fdsを反復しています。

if (FD_ISSET(fifo, &read_fds)) { 

ここでは、fifoが読み取り可能かどうかをテストしています。毎回ループの周り。初めて、あなたは何かを読んで、それを送ります。次回ループの周りでFIFOに何も起こっていませんが、上記の条件がまだ成立しているので、再度読んでEAGAINを取得してください。

このifブロックはループの外側と下方にある必要があります。

+0

私は今理解しており、それは完全に問題を解決しました。ありがとう! –

関連する問題