進階 I/O 涵蓋非阻塞 I/O、有限狀態機、I/O 多路複用、記錄鎖、非同步 I/O、readv/writev、存儲映射 I/O 等核心主題,是高效能網路程式開發的基石。
使用 O_NONBLOCK 旗標開啟檔案,read/write 無資料時立即返回 EAGAIN,而非阻塞等待。需在迴圈中處理假錯誤 EINTR(訊號中斷)與 EAGAIN:
fd = open("/etc/service", O_RDONLY | O_NONBLOCK);
while (1) {
size = read(fd, buf, BUFSIZE);
if (size < 0) {
if (errno == EAGAIN) continue; // 假錯誤,重試
perror("read()"); exit(1);
}
// 處理資料...
}
將複雜流程抽象為狀態與轉移,適合處理非結構化流程(如網路協議)。核心元素:
STATE_R(讀)、STATE_W(寫)、STATE_Ex(異常)、STATE_T(結束)switch(state) 根據當前狀態執行對應邏輯並轉移狀態範例實現雙向 TTY 轉發:讀 tty11 寫 tty12,反之亦然,透過狀態機協調雙向資料流。
解決忙等待問題,三種方案比較:
| 特性 | select | poll | epoll |
|---|---|---|---|
| 可攜性 | 最高 (POSIX) | 良好 | Linux 專有 |
| 檔案描述符上限 | 1024 (FD_SETSIZE) | 無硬性限制 | 無硬性限制 |
| 效能模型 | 輪詢 O(n) | 輪詢 O(n) | 事件通知 O(1) |
| 核心資料結構 | 位圖 fd_set | pollfd 陣列 | 紅黑樹 + 就緒列表 |
fd_set rset, wset;
while (fsm12.state != STATE_T || fsm21.state != STATE_T) {
FD_ZERO(&rset); FD_ZERO(&wset);
if (fsm12.state == STATE_R) FD_SET(fsm12.sfd, &rset);
if (fsm12.state == STATE_W) FD_SET(fsm12.dfd, &wset);
// ... 同樣處理 fsm21
if (select(max(fd1,fd2)+1, &rset, &wset, NULL, NULL) < 0) { /* 錯誤處理 */ }
if (FD_ISSET(fd1, &rset) || FD_ISSET(fd2, &wset) || fsm12.state > STATE_AUTO)
fsm_driver(&fsm12);
if (FD_ISSET(fd2, &rset) || FD_ISSET(fd1, &wset) || fsm21.state > STATE_AUTO)
fsm_driver(&fsm21);
}
使用 epoll_create/epoll_ctl/epoll_wait,核心管理監控集合,支援海量連線,epoll_data_t 可攜帶用戶資料(如樹節點指標),是高併發伺服器首選。
將檔案映射至記憶體,像操作陣列一樣存取檔案:
str = mmap(NULL, statres.st_size, PROT_READ, MAP_SHARED, fd, 0); // 直接用 str[i] 存取檔案內容 munmap(str, statres.st_size);
共享記憶體技巧:使用 MAP_ANONYMOUS | MAP_SHARED 配合 fork 實現父子進程高效共享記憶體,比 System V 共享記憶體更簡便。
flock:整個檔案建議性鎖,支援共享/獨佔模式lockf:區域鎖(從當前位置鎖定長度),支援阻塞/非阻塞/測試/解鎖範例:20 進程並發累加檔案計數器,使用 lockf(fd, F_LOCK, 0) 保護臨界區。
readv/writev:分散/聚集 I/O,單次系統呼叫處理多個緩衝區readn/writen:確保讀寫足夠位元組的封裝函數掌握進階 I/O 能顯著提升網路程式效能與健壯性,是系統程式設計師必備技能。