一、前言

在 Linux 网络 / 系统编程中,select 是最经典的 I/O 多路复用技术。 它能让单线程同时监听多个文件描述符,并且支持设置超时时间,非常适合:

  • 同时监听键盘、网络套接字
  • 不阻塞死等,超时自动返回
  • 轻量场景下替代多线程

这里用最简单的例子监听标准输入(键盘),5 秒无输入就超时打印 time out 带你彻底搞懂 select 的核心用法。


二、核心知识点

1. select 函数原型

#include <sys/select.h>

int select(
    int nfds,
    fd_set *readfds,   // 监听“可读”的fd集合
    fd_set *writefds,  // 监听“可写”的fd集合
    fd_set *exceptfds, // 监听“异常”的fd集合
    struct timeval *timeout // 超时时间
);

2. fd_set:文件描述符集合(位图)

本质是位图,每一位代表一个文件描述符(fd)。 提供 4 个宏来操作:

FD_ZERO(&set);        // 清空集合(全部置0)
FD_SET(fd, &set);     // 把fd加入集合(对应位置1)
FD_CLR(fd, &set);     // 把fd移出集合
FD_ISSET(fd, &set);   // 判断fd是否在集合中(是否就绪)

3. struct timeval:超时结构体

struct timeval {
    long tv_sec;   // 秒
    long tv_usec;  // 微秒(1秒=1e6微秒)
};

三种超时模式:

  • NULL无限阻塞,直到有事件
  • {0,0}非阻塞,立即返回
  • {5,0}阻塞最多 5 秒,超时返回 0

4. select 返回值

  • >0:有 fd 就绪,返回就绪个数
  • =0超时,无事件
  • -1:出错(如被信号中断)

三、完整代码

代码使用 select 实现 5 秒超时监听键盘输入,逻辑简单清晰,适合入门学习

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>

#define   STDIN  0

int main()
{
    int fd = STDIN;//键盘对应的描述符
    fd_set fdset;//集合,收集描述符

    while( 1 )
    {
        FD_ZERO(&fdset);//清空集合
        FD_SET(fd,&fdset);//将键盘对应的描述符添加到集合fdset中

        struct timeval tv = {5,0};

        int n = select(fd+1,&fdset,NULL,NULL,&tv);//select可能阻塞,最长阻塞5s
        if( n == -1)
        {
            printf("select err\n");
        }
        else if ( n == 0 )
        {
            printf("time  out\n");
        }
        else
        {
            if( FD_ISSET(fd,&fdset))
            {
                char buff[128] = {0};
                read(fd,buff,127);
                printf("read:%s\n",buff);
            }
        }

    }
}

四、运行结果

(启动后,不操作键盘)
time out          ← 第1个5秒到
time out          ← 第2个5秒到
hello             ← 输入hello+回车
read: hello
time out          ← 第3个5秒到
test123           ← 输入test123+回车
read: test123
  • 无输入 → 每 5 秒打印 time out
  • 有输入 → 立刻读取并打印
  • 退出 → 按 Ctrl+C

五、select 的优缺点(面试 / 总结用)

优点

✅ 跨平台(Linux/Windows/macOS 都支持)

✅ 简单易用,适合入门 I/O 多路复用

✅ 支持超时,避免无限阻塞

缺点

❌ 最大监听数受限(默认 1024,FD_SETSIZE

❌ 每次循环要重置 fd 集合,效率低

❌ 返回后需遍历集合找就绪 fd,开销大


六、总结

select 是 Linux IO 多路复用的基础技术,解决了单线程阻塞等待单个 IO 的问题,可实现多 IO 统一监听并灵活设置超时。本次案例帮助我理解了文件描述符、集合操作、超时配置等基础概念,为后续学习网络编程、pollepoll 等进阶 IO 模型打下了基础

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐