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

Linux I/O 多路復用:select 模型原理與實戰詳解

     編輯:C++ 入門

Linux I/O 多路復用:select 模型原理與實戰詳解

I/O 多路復用是高性能網絡編程的基石,允許單線程同時監聽多個文件描述符。select 是最經典、可移植性最強的實現。本文深入解析其數據結構、API 細節、超時控制及完整服務器示例。

一、 核心數據結構:fd_set

fd_set 本質是一個長整型數組,每個 bit 標記一個文件描述符。容量由 FD_SETSIZE 定義(通常 1024),限制了 select 最大監聽數。

四大操作宏(必須使用,避免直接位操作):

  • FD_ZERO(fd_set *set):清空集合。
  • FD_SET(int fd, fd_set *set):添加 fd。
  • FD_CLR(int fd, fd_set *set):移除 fd。
  • FD_ISSET(int fd, fd_set *set):檢測 fd 是否就緒。

二、 select 系統調用詳解

#include 
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

參數詳解

  • nfds:監聽的 fd 最大值 + 1(因 fd 從 0 開始)。
  • readfds/writefds/exceptfds:傳入關注集,**調用返回時被內核修改為就緒集**。傳 NULL 表示不關注該類事件。
  • timeout:
    • tv_sec=0, tv_usec=0:非阻塞輪詢,立即返回。
    • NULL:永久阻塞,直到有事件發生。
    • 具體時間值:超時返回 0。

返回值

  • >0:就緒描述符總數(三個集合之和)。
  • =0:超時無就緒。
  • -1:錯誤,查 errno(如 EINTR 被信號中斷需重試)。

三、 實戰:同時處理普通數據與帶外數據

TCP 帶外數據(OOB)觸發 異常條件,普通數據觸發 可讀條件。利用 exceptfds 區分。

int main(int argc, char *argv[]) {
    // ... socket, bind, listen, accept 省略 ...
    int connfd = accept(listenfd, ...);
    
    fd_set readSet, exceptSet;
    char buf[1024];
    
    while (1) {
        FD_ZERO(&readSet);
        FD_ZERO(&exceptSet);
        FD_SET(connfd, &readSet);
        FD_SET(connfd, &exceptSet);
        
        int ret = select(connfd + 1, &readSet, NULL, &exceptSet, NULL);
        if (ret < 0) { perror("select"); break; }
        
        if (FD_ISSET(connfd, &readSet)) {
            ret = recv(connfd, buf, sizeof(buf), 0);
            if (ret <= 0) break;
            printf("普通數據: %.*s\n", ret, buf);
        } else if (FD_ISSET(connfd, &exceptSet)) {
            ret = recv(connfd, buf, sizeof(buf), MSG_OOB);
            if (ret <= 0) break;
            printf("帶外數據(OOB): %.*s\n", ret, buf);
        }
    }
    close(connfd);
    return 0;
}

四、 select 的局限性與演進

工程建議:連接數 < 1000 且跨平台需求強 → select;Linux 高併發 → epoll;跨平台高併發 → libevent/libuv 封裝庫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
缺點影響後繼者解決方案
fd_set 大小固定 (FD_SETSIZE)無法監聽 >1024 fdpoll 無限制;epoll 紅黑樹管理
每次調用需全量拷貝 fd_set 到內核O(n) 開銷大poll 同樣;epoll 共享內存/就緒隊列
返回後需全量掃描 fd_set 找就緒 fdO(n) 掃描開銷epoll 返回就緒列表 O(1) 遍歷
水平觸發 (LT) 模式固定需循環讀寫直到 EAGAINepoll 支持邊緣觸發 (ET) 高效模式