2012-05-11 16 views
1

linuxのepoll通知機能の詳細については、httpサーバで作業しています。サーバーの構造は基本的に要求を表すイベント構造体の配列を持ち、いくつかのネストされたforループとwhileループで反復処理されます。epoll_ctlが私に悪いfdを持っていると言っているのはなぜですか?

この最初のイベントループを初めて書いたとき、かなりうまくいきました。しかし、コードをリファクタリングすると、ループの信頼性が大幅に低下します。特に、私はepoll_ctlエラーの束(要求の約75%)を得始めました。errnoはBADFDに設定されています。 epoll_ctlは私のソケットファイル記述子が実際にソケットファイル記述子ではないと確信しています。

リファクタがa)要求の解析をクリーンアップし、b)メイン関数をプログラムの先頭まで移動させるだけなので、パフォーマンスが低下する理由は本当に混乱しています。私はサーバーの前回のコミットをチェックアウトし、新しいバージョンとの主な機能を比較しました - それは同じです。

ここで何が起きているのかについて誰かが洞察していますか?それは評価されるだろう。ここで

は参照用のメイン関数のコードです:

int main(int argc, char *argv[]) { 
    c("in main"); 
    char *progname=argv[0]; 
    int sockfd, newsockfd, portno, clilen, n, pid, epollfd; 
    struct sockaddr_in serv_addr, cli_addr; 

    initFt(); 
    if (argc < 2) { 
     fprintf(stderr, "\nERROR: No Port Provided\n"); 
     exit(EXIT_FAILURE); 
    } 
    if (!createSocket(&sockfd)) { 
     fprintf(stderr, "%s ERROR, COULD NOT CREATE SERVER SOCKET\n", progname); 
     exit(EXIT_FAILURE); 
    } 

    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_port = htons(atoi(argv[1])); 
    serv_addr.sin_addr.s_addr = INADDR_ANY; 
    Bind(&sockfd, &serv_addr); 
    listen(sockfd, 5); 

    struct epoll_event *events = calloc(SOMAXCONN, sizeof(struct epoll_event)); 
    struct epoll_event event; 
    makeSocketNB(&sockfd); 
    event.events = EPOLLIN | EPOLLET; 
    event.data.fd = sockfd; 

    if ((epollfd = createpoll())<0) { 
     fprintf(stderr, "epoll create error\n"); 
     exit(EXIT_FAILURE); 
    } 
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &event) == -1) { 
     fprintf(stderr, "error with epoll_ctl on sockfd"); 
     exit(EXIT_FAILURE); 
    } 

    while (1) { 
     int n, e; //e for events 
     e = epoll_wait(epollfd, events, SOMAXCONN, -1); 

     for (n=0; n<e; n++) { 
      if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP) || !(events[n].events & EPOLLIN)) { 
       fprintf (stderr, "epoll error\n"); 
       close (events[n].data.fd); 
       continue; 
      } 
      else if (events[n].data.fd == sockfd) { 
       while (1) { 
        newsockfd=accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); 
        if (newsockfd>0) { 
         makeSocketNB(&newsockfd); 
         fprintf(stderr, "Accepted a new connection on fd %d, made nonblocking\n", newsockfd); 
        } 
        else if (errno == EAGAIN || errno == EWOULDBLOCK) { 
         fprintf (stderr, "we have accepted all the clients on this event\n"); 
         break; 
        } 
        event.data.fd = newsockfd; 
        event.events = EPOLLIN | EPOLLET; 
        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, newsockfd, &event)<0) { 
         fprintf(stderr, "epoll_ctl error\n"); 
         if (errno == EEXIST) { 
          fprintf(stderr, "fd already registered\n"); 
         } 
         else if (errno == EBADF) { 
          fprintf(stderr, "fd bad\n%d\n", newsockfd); 
          break; 
         } 
         else if (errno == ENOMEM) { 
          fprintf(stderr, "no memory\n"); 
         } 
         else if (errno == ENOSPC) { 
          fprintf(stderr, "enospc\n"); 
         } 
         exit(EXIT_FAILURE); 
        } 
        continue; 
       } 
      } 
      else { // there is stuff for us to read 
       handleResponse(&events[n].data.fd); 
       fprintf(stderr, "we are about to close file descriptor %d\n", events[n].data.fd); 
       close (events[n].data.fd); 
       fprintf(stderr, "connection closed\n"); 
      } 
     } 
    } 

    exit(EXIT_SUCCESS); 
} 
+1

ポストにコードの書式を修正するには、しばらく時間がかかることがあります。人々はそれを読んでフィードバックを出す可能性が高くなります。 –

答えて

2

あなたacceptコードは実際にエラーを処理しません。それだけで「成功」の場合とwouldblockのケースを処理します。

if (newsockfd>0) { 
    /* success */ 
} else if (errno == EAGAIN || errno == EWOULDBLOCK) { 
    /* wouldblock */ 
} 

/* Could be error but you call `epoll_ctl` anyway. */ 
+0

これは問題を解決するようですが、なぜacceptがmain関数の位置によって異なって振る舞うのかまだ分かりません。 –

関連する問題