2017-10-13 71 views
0

得到所以我有一些代碼,看起來像這樣:epoll_wait似乎停留在EPOLLRDHUP

for (;;) { 
     errno=0; 
     epoll_event e = {}; 
     auto wait_r = epoll_wait(g.epoll_fd, &e, 1, 0); 
     if (wait_r==0) break; 
     if(wait_r ==-1 && errno==EINTR) { 
      printf("got EINTR\n"); 
      continue; 
     } 
     assert(wait_r == 1); 

     auto& c = *(Context*)e.data.ptr; 

     if(e.events & EPOLLERR) { 

      int  error = 0; 
      socklen_t errlen = sizeof(error); 
      auto r1 =getsockopt(c.socket, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen); 
      assert(r1==0); 
      printf("Got EPOLLERR 2 %s\n", strerror(error)); 
     } 


     if(e.events & EPOLLRDHUP || e.events & EPOLLHUP) { 
      if (e.events & EPOLLRDHUP) { 
       printf("got to EPOLLRDHUP\n"); 
      } 
      if (e.events & EPOLLHUP) { 
       printf("got to EPOLLHUP\n"); 
      } 
      //continue; // keeps hitting this for same connections 
      break; 
     } 

     if (e.events & EPOLLIN) { 

      // Does a bunch of reads... 
     } 
    } 
} 

一個單一的插座將被陷在EPOLLRDHUP || EPOLLHUP情況。當我嘗試關閉它或執行EPOLL_CTL_DEL時,套接字可能會關閉,我得到一個EBADFD。這是我的理解,epoll會自動消除任何死亡的套接字,但這似乎並非如此......任何想法?

另一個可能的問題是,在套接字上我使用的是recvmsg/sendmsg,而且我正在通過這些套接字(它們是unix域流套接字)在進程之間發送文件描述符。我試圖做一個最後的recvmsg,但也失敗了......任何想法?

+0

我建議您的代碼在完成處理「EPOLLHUP」事件之前調用'close'。請注意,'EPOLLHUP'表示對方已關閉連接 - 但您的代碼尚未關閉連接。由於'fd'仍然打開,'epoll'將繼續輪詢它。 – Myst

+0

@myst當我嘗試關閉它時,在這種情況下,它會以錯誤的文件描述符失敗。但是,感謝您對一般情況的建議。 –

+0

我確定你的代碼必須關閉客戶端'fd'(而不是'g.epoll_fd')才能釋放它的資源。你的代碼並不是一個完整的例子,所以我可以評論多少。我不確定哪個函數調用會導致'EBADFD'或者你傳遞給'close'的值。事實上,我甚至不確定你存儲事件的'fd'值的位置。您可以將它存儲在事件中,但我有時會使用該事件來存儲指向包含「fd」數據以及其他信息的對象的指針......並且可能會因爲您沒有將其存儲在任何地方而發生錯誤。我不知道。 – Myst

回答

0

對於我的問題,解決辦法是改變這樣一行:

c.socket = accept(g.server_socket, NULL, NULL); 

這樣:

c.socket = accept4(g.server_socket, NULL, NULL, SOCK_CLOEXEC); 

如果任何人有這個問題,尋找出dup()exec()電話。 A dup()可能導致epoll表現爲未關閉,即使您已關閉了添加到epoll的fd。 epoll只會識別出一旦關閉了fd的所有副本,它就會關閉。 exec()基本上會做與dup()相同的事情,對於您沒有使用SOCK_CLOEXEC標誌創建的每個fd都是如此。