首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

APUE 進階 I/O 完整指南:非阻塞、狀態機、多路複用與記憶體映射

     編輯:關於C語言

Unix 環境高級編程(APUE)第 14 章:進階 I/O 深度解析

進階 I/O 涵蓋非阻塞 I/O、有限狀態機、I/O 多路複用、記錄鎖、非同步 I/O、readv/writev、存儲映射 I/O 等核心主題,是高效能網路程式開發的基石。

1. 非阻塞 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);
    }
    // 處理資料...
}

2. 有限狀態機 (FSM)

將複雜流程抽象為狀態與轉移,適合處理非結構化流程(如網路協議)。核心元素:

  • 狀態枚舉:STATE_R(讀)、STATE_W(寫)、STATE_Ex(異常)、STATE_T(結束)
  • 狀態結構體:包含檔案描述符、緩衝區、位移、錯誤訊息等
  • 驅動函數:switch(state) 根據當前狀態執行對應邏輯並轉移狀態

範例實現雙向 TTY 轉發:讀 tty11 寫 tty12,反之亦然,透過狀態機協調雙向資料流。

3. I/O 多路複用

解決忙等待問題,三種方案比較:

特性selectpollepoll
可攜性最高 (POSIX)良好Linux 專有
檔案描述符上限1024 (FD_SETSIZE)無硬性限制無硬性限制
效能模型輪詢 O(n)輪詢 O(n)事件通知 O(1)
核心資料結構位圖 fd_setpollfd 陣列紅黑樹 + 就緒列表

select 版本關鍵修改

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 版本優勢

使用 epoll_create/epoll_ctl/epoll_wait,核心管理監控集合,支援海量連線,epoll_data_t 可攜帶用戶資料(如樹節點指標),是高併發伺服器首選。

4. 記憶體映射 I/O (mmap)

將檔案映射至記憶體,像操作陣列一樣存取檔案:

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 共享記憶體更簡便。

5. 檔案鎖

  • flock:整個檔案建議性鎖,支援共享/獨佔模式
  • lockf:區域鎖(從當前位置鎖定長度),支援阻塞/非阻塞/測試/解鎖

範例:20 進程並發累加檔案計數器,使用 lockf(fd, F_LOCK, 0) 保護臨界區。

6. 其他進階函數

  • readv/writev:分散/聚集 I/O,單次系統呼叫處理多個緩衝區
  • readn/writen:確保讀寫足夠位元組的封裝函數

掌握進階 I/O 能顯著提升網路程式效能與健壯性,是系統程式設計師必備技能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved