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- n = 0;
- while ((nread = read(fd, buf + n, BUFSIZ-1)) > 0) {
- n += nread;
- }
- if (nread == -1 && errno != EAGAIN) {
- perror("read error");
- }
正確的寫: