Linux select入门:5秒监听键盘输入
·
一、前言
在 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 统一监听并灵活设置超时。本次案例帮助我理解了文件描述符、集合操作、超时配置等基础概念,为后续学习网络编程、poll、epoll 等进阶 IO 模型打下了基础
更多推荐




所有评论(0)