2011-02-04 13 views
3

後、私は次のような問題を持っているのrecvながら:私は接続を受けるのepollコードを持っている:EBADFがepoll_wait

while (1) { 
    int nfds = epoll_wait(epollfd, events, 4096, -1); 
    if (nfds == -1) { 
     if (errno == EINTR) 
      continue; 
     perror("epoll_wait"); 
     exit(EXIT_FAILURE); 
    } 

    for (int i = 0; i < nfds; i++) { 
     if (events[i].data.fd == server_sock) { 
      client_sock = accept(server_sock, 
         (struct sockaddr *)&client_name, 
         (socklen_t *)(&client_name_len)); 

     if (client_sock == -1) //server overloaded 
      continue; 

     ev.events = EPOLLIN | EPOLLERR; 

#ifdef CORE_NONBLOCKING_SOCKETS 
     Arch::set_nonblocking(client_sock); 
     ev.events |= EPOLLET; //input data and connection closing 
#endif 


#ifdef EPOLLRDHUP 
     ev.events |= EPOLLRDHUP ;// 
#else 
     //for old libraries 
     ev.events |= EPOLLHUP;// 
#endif 

     ev.data.fd = client_sock; 

     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, client_sock, &ev) == -1) { 
      perror("epoll_ctl: client_socket"); 
      exit(EXIT_FAILURE); 
     } 

     accept_request(client_sock); 

     } else { 

#ifdef EPOLLRDHUP 
      if (events[i].events & EPOLLRDHUP) { 
       std::cout << "EPOLLRDHUP on " << events[i].data.fd << std::endl; 
       listener->disconnectDriver(events[i].data.fd); 
      } 
#else 
      if (events[i].events & EPOLLHUP) { 
       std::cout << "EPOLLHUP on " << events[i].data.fd << std::endl; 
       listener->disconnectDriver(events[i].data.fd); 
      } 
#endif 
      if (events[i].events & EPOLLIN) { 
       std::cout << "debug EPOLLIN on " << events[i].data.fd << std::endl; 
       accept_request(events[i].data.fd); 
      } 

      if (events[i].events & EPOLLERR) { 
       std::cout << "debug EPOLLERR on " << events[i].data.fd << std::endl; 
       listener->disconnectDriver(events[i].data.fd); 
      } 


     } 
    } 

私はすべてのバフデータを読み込もうとした入力接続を受信するとき:

void get_all_buf(int sock, std::string & inStr) { 
int n = 1; 
int total = 0; 

char c; 
char temp[1024*1024]; 

bzero(temp, sizeof(temp)); 

do { 
#ifdef CORE_NONBLOCKING_SOCKETS 
    timespec time_to_wait; 
    time_to_wait.tv_nsec = 10000000; 
    time_to_wait.tv_sec = 0; 
    timespec tm; 

    time_t begin = time(NULL); 
    do { 
#endif 

     n = recv(sock, &temp[total], sizeof(temp), 0); 

#ifdef CORE_NONBLOCKING_SOCKETS 
     nanosleep(&time_to_wait, &tm); 
     time_t end = time(NULL); 
     if ((end - begin) > MAX_CLIENT_TIME) { 
      inStr = std::string(); 
      return; 
     } 
    } while (n < 0 && errno == EAGAIN); //nonblocking sockets in edge-triggered mode 
#endif 

    if (n > 0) { 
     total += n; 
    } else if (n == 0) { 
     //TODO: error handling 
     //debug 
     std::cout << "possibly no one byte was received" << std::endl; 
     break; 
    } else if (n < 0) { 
     //TODO: error handling 
     //debug 
     std::cout << "error while receiving data" << std::endl; 
     if (errno == EBADF) { 
      std::cout << "recv returns with EBADF: " << strerror(errno) << std::endl; 
     } else if (errno == EFAULT) { 
      std::cout << "recv returns with EFAULT: " << strerror(errno) << std::endl; 
     } else if (errno == EINTR) { 
      std::cout << "recv returns with EINTR: " << strerror(errno) << std::endl; 
     } else if (errno == EINVAL) { 
      std::cout << "recv returns with EINVAL: " << strerror(errno) << std::endl; 
     } 
     //end debug 
     break; 
    } 

} while (!strstr(temp, "</packet>")); 
inStr = temp; 
}; 

以内accept_request機能です。しかし、いつか私は私のデバッグ出力に次を得る:

packet type='connect' 
size of vector<Driver> in getDriversWithMoney is 1 
epoll_wait detected activity of 164 counter i = 0 nfds = 1 
EPOLLRDHUP on 164 
disconnectDriver (fd = 164) 
driver 1 disconnected 
debug EPOLLIN on 164 
error while receiving data 
recv returns with EBADF: Invalid file descriptor 

誰かが最初の切断よりも接続されていたし、彼は再びrecv戻りEBADFを接続しようとしたときにことを意味しています。私は何を間違えたの?私を助けてください。

P.S. on EPOLLRDHUPファイル記述子を閉じるだけです。 epollは、epollは、epoll_waitキューからクローズドfdを単独で削除するので、大丈夫です。

+0

'strace'ログを取得してみてください。問題の詳細はこちら – bdonlan

+0

ationは定期的ではありません。それはしばらく後になった。 – milo

+0

これは、straceが便利な場所です。プログラムのどの入力から、それがどのように動作するのかを示しています。 –

答えて

7

リモートホストがソケットを閉じると、epoll()はファイルディスクリプタとしてHUPEPOLLINの両方を報告します。

最初にEPOLLRDHUPをチェックし、ソケットを閉じます。 EPOLLINをチェックし、それも見つけてrecv()に電話してみてください。ソケットは閉じられているため、ファイル記述子は無効になり、EBADF(閉じたソケットはepollのセットから削除されるため、の後に続きます。epoll_wait()呼び出しは返されませんが、すでに返されたepoll_wait()それは手遅れ - EPOLLINはすでにevents[i]に待っているあなたが(それはファイルディスクリプタを閉じた場合)あなたがdisconnectDriver()を呼び出した後、イベントのチェックを停止する必要が

 if (events[i].events & EPOLLRDHUP) { 
      std::cout << "EPOLLRDHUP on " << events[i].data.fd << std::endl; 
      listener->disconnectDriver(events[i].data.fd); 
      continue; 
     } 
+0

そこによく見られます。 – MarkR

+0

ありがとうございます!あなたは私をとても助けました! – milo

関連する問題