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

Linux I/O 多路復用:select() 系統調用完整詳解

     編輯:關於C語言

Linux I/O 多路復用:select() 系統調用完整詳解

select() 允許進程同時監控多個文件描述符 (I/O 設備),任一就緒即返回;無就緒時阻塞。

函數原型

#include <sys/select.h>
#include <sys/time.h>

int select(int maxfd,
           fd_set *readfds,
           fd_set *writefds,
           fd_set *exceptfds,
           struct timeval *timeout);

參數詳解

  • maxfd:被監控的最大文件描述符值 **+1** (因描述符從 0 開始)。
  • readfds:關注**讀就緒**的描述符集。
  • writefds:關注**寫就緒**的描述符集。
  • exceptfds:關注**異常條件**(如帶外數據)的描述符集。
  • timeout:定時器。
    • NULL:無限阻塞,直到有就緒。
    • tv_sec=0, tv_usec=0:非阻塞,立即返回 (輪詢)。
    • 正值:最長等待時間。

timeval 結構

struct timeval {
    long tv_sec;   // 秒
    long tv_usec;  // 微秒
};

返回值

  • > 0:就緒描述符總數。
  • 0:超時,無就緒。
  • -1:出錯 (errno 指示) 或被信號中斷 (EINTR)。

關鍵:返回時,readfds/writefds/exceptfds 被**修改**,僅保留就緒的描述符,非就緒位被清零。

描述符集操作宏

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 後使用)

標準使用流程

fd_set fds;
FD_ZERO(&fds);
FD_SET(fd1, &fds);
FD_SET(fd2, &fds);
int maxfdp = (fd1 > fd2 ? fd1 : fd2) + 1;

struct timeval tv = {5, 0}; // 5 秒超時

int ret = select(maxfdp, &fds, NULL, NULL, &tv);
if (ret == -1) { perror("select"); exit(1); }
if (ret == 0) { printf("Timeout\n"); return 0; }

if (FD_ISSET(fd1, &fds)) { /* fd1 可讀 */ }
if (FD_ISSET(fd2, &fds)) { /* fd2 可讀 */ }

完整可運行示例

監控標準輸入 (STDIN_FILENO) 與一個文件 (test.txt):

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#define TIMEOUT 5
#define BUF_LEN 1024

int main() {
    fd_set readfds;
    int fd_file = open("test.txt", O_RDONLY);
    if (fd_file == -1) { perror("open"); return 1; }

    FD_ZERO(&readfds);
    FD_SET(STDIN_FILENO, &readfds);
    FD_SET(fd_file, &readfds);
    int maxfdp = (STDIN_FILENO > fd_file ? STDIN_FILENO : fd_file) + 1;

    struct timeval tv = {TIMEOUT, 0};
    int ret = select(maxfdp, &readfds, NULL, NULL, &tv);
    if (ret == -1) { perror("select"); return 1; }
    if (ret == 0) { printf("Timeout %d sec\n", TIMEOUT); return 0; }

    char buf[BUF_LEN + 1];
    if (FD_ISSET(STDIN_FILENO, &readfds)) {
        int len = read(STDIN_FILENO, buf, BUF_LEN);
        if (len > 0) { buf[len] = '\0'; printf("Stdin: %s", buf); }
    }
    if (FD_ISSET(fd_file, &readfds)) {
        int len = read(fd_file, buf, BUF_LEN);
        if (len > 0) { buf[len] = '\0'; printf("File: %s", buf); }
    }
    close(fd_file);
    return 0;
}

GCC 編譯運行無誤。程序等待 5 秒,期間鍵盤輸入或文件可讀即處理。

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