一些入門知識,不寫下來容易忘
一般使用 poll 檢測 socket 或标準輸入時,隻要指定 POLLIN 标志位,就可以檢測是否有資料到達,或者連接配接斷開:
1 struct pollfd fds[3];
2 fds[0].fd = STDIN_FILENO;
3 fds[0].events = POLLIN;
4 fds[1].fd = sock_fd;
5 fds[1].events = POLLIN;
6 fds[2].fd = pipe_fd;
7 fds[2].events = POLLIN;
8 ret = poll(fds, 3, -1);
9 if (ret > 0) {
10 if (fds[0].revents & POLLIN) {
11 // handle stdin
12 ...
13 }
14 if (fds[1].revents & POLLIN) {
15 // handle socket input
16 ...
17 }
18 if (fds[2].revents & POLLIN) {
19 // handle pipe input
20 ...
21 }
22 }
當 read 結果傳回 0 時表示相應連接配接斷開。
而對于 pipe,隻檢測POLLIN是感覺不到管道斷開的,當管道斷開時,會在revents設定POLLHUP,必需額外檢測此标志位:
1 if (pfd[2].revents & POLLHUP) {
2 // handle pipe break
3 ...
4 }
而當 poll 一個已經關閉的句柄時(句柄号 >=0 有效),poll 本身并不傳回錯誤,而是給對應的句柄事件中設定 POLLNVAL 标志位:
1 if (pfd[2].revents & POLLNVAL) {
2 // handle pipe close
3 ...
4 }
若 poll 一個無效句柄時(句柄号為-1),poll 本身仍不傳回錯誤,但該句柄一定沒有任何事件可供檢測與傳回。是以可用于占位處理,
例如固定從數組某個下标中取出某個句柄時可以在不相關位置設定-1句柄,這樣就不用再去判斷目前有事件的句柄的源句柄是哪一個了:
1 struct pollfd fds[3];
2 fds[0].fd = STDIN_FILENO;
3 fds[0].events = POLLIN;
4 fds[1].fd = -1;
5 fds[1].events = POLLIN;
6 fds[2].fd = pipe_fd;
7 fds[2].events = POLLIN;
8 ret = poll(fds, 3, -1);
9 ……
例如當沒有 socket 句柄時,該位置保持-1,這樣可以不用将管道句柄上移,進而可以固定從fds[2]中取出管道句柄。
當然如果傳入 poll 的句柄數組中所有句柄都為無效句柄時,poll仍不傳回錯誤,此時若提供逾時,可當成sleep使用;
若不提供逾時,則會進入無限期等待……
測試代碼