1. 程式人生 > >UNIX網路程式設計——epoll 的accept , read, write

UNIX網路程式設計——epoll 的accept , read, write

總結:

       這個錯誤表示資源暫時不夠,可能read時, 讀緩衝區沒有資料, 或者write時,寫緩衝區滿了。 

       遇到這種情況,如果是阻塞socket、 read/write就要阻塞掉。而如果是非阻塞socket、 read/write立即返回-1, 同 時errno設定為EAGAIN。

       所以對於阻塞socket、 read/write返回-1代表網路出錯了。但對於非阻塞socket、read/write返回-1不一定網路真的出錯了。可能是Resource temporarily unavailable。這時你應該再試,直到Resource available。

       綜上, 對於non-blocking的socket,正確的讀寫操作為:

  • 讀: 忽略掉errno = EAGAIN的錯誤,下次繼續讀 
  • 寫:忽略掉errno = EAGAIN的錯誤,下次繼續寫 

       對於select和epoll的LT模式,這種讀寫方式是沒有問題的。 但對於epoll的ET模式,這種方式還有漏洞。

epoll的兩種模式 LT 和 ET

       二者的差異在於 level-trigger 模式下只要某個 socket 處於 readable/writable 狀態,無論什麼時候進行 epoll_wait 都會返回該 socket;而 edge-trigger 模式下只有某個 socket 從 unreadable 變為 readable 或從unwritable 變為 writable 時,epoll_wait 才會返回該 socket。如下兩個示意圖:

      從socket讀資料:

                                                             

       往socket寫資料:

                                                             

       所以在epoll的ET模式下,正確的讀寫方式為:

  • 讀: 只要可讀, 就一直讀,直到返回0,或者 errno = EAGAIN
  • 寫:只要可寫, 就一直寫,直到資料傳送完,或者 errno = EAGAIN

正確的讀:

[cpp] view plain
copyprint?
  1. n = 0;    
  2. while ((nread = read(fd, buf + n, BUFSIZ-1)) > 0) {    
  3.     n += nread;    
  4. }    
  5. if (nread == -1 && errno != EAGAIN) {    
  6.     perror("read error");    
  7. }    

 正確的寫: