Linux下读取/proc/self/fd是唯一可行的通用方法,需结合opendir/readdir遍历纯数字fd项,用readlink获取路径,再通过fcntl(F_GETFD/F_GETFL)获取标志位,并解析伪路径字符串区分socket、pipe等类型。

Linux下读取/proc/self/fd是唯一可行的通用方法
Windows没有等价的“文件描述符”抽象,C++标准库也不提供跨平台枚举FD的接口。在Linux上,/proc/self/fd是内核暴露的实时视图,它本质是符号链接目录,每个条目指向对应FD打开的文件路径或设备节点。注意:这不是快照,而是动态视图;遍历过程中FD可能被关闭或新建,需容忍readlink返回ENOENT。
关键点:
-
opendir("/proc/self/fd")必须成功,否则进程可能被chroot或/proc未挂载 - 每个
d_name是数字字符串(如"0"、"15"),需strtol转为int获取FD号 -
readlink()目标路径格式为"/proc/self/fd/123",返回值是实际路径或伪路径(如socket:[12345]、pipe:[67890]) - 无法直接得知“状态”(如是否阻塞、是否可写),这些属于fd标志,需额外调用
fcntl(fd, F_GETFL)
用fcntl(fd, F_GETFD)和fcntl(fd, F_GETFL)补全FD元信息
仅靠/proc/self/fd链接目标无法区分O_RDONLY/O_WRONLY/O_RDWR,也无法知道FD_CLOEXEC标志。必须对每个有效FD号调用两次fcntl:
-
fcntl(fd, F_GETFD)返回文件描述符标志,检查FD_CLOEXEC位判断是否设置close-on-exec -
fcntl(fd, F_GETFL)返回文件状态标志,用O_ACCMODE掩码提取访问模式(O_RDONLY、O_WRONLY、O_RDWR),再按位与O_APPEND、O_NONBLOCK等判断具体行为 - 调用前需用
dup(fd)测试FD是否仍有效——若dup失败(EBADF),说明该FD已在遍历中被关闭,跳过后续fcntl
识别socket、pipe、eventfd等特殊类型要解析readlink返回字符串
readlink对特殊对象不返回真实路径,而是固定格式伪路径,需字符串匹配:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
- 以
"socket:["开头 → TCP/UDP/unix socket,括号内数字是inode号,可进一步查/proc/net/{tcp,tcp6,unix}关联协议细节 - 以
"pipe:["开头 → 匿名管道,inode号可用于在/proc/self/fdinfo/下查读写端计数 - 以
"anon_inode:"开头(如"anon_inode:inotify")→ 内核匿名inode对象,常见于inotify、eventfd、timerfd - 返回
"(deleted)"后缀 → 文件已被unlink但FD仍打开(常见于日志轮转场景)
注意:readlink缓冲区必须足够大(建议4096字节),否则截断导致误判。
不要尝试lsof -p $$或ss -lp替代,它们不可靠且开销大
调用外部命令看似简单,但存在严重问题:
-
lsof需要root权限才能看到其他用户进程的FD,且自身会打开大量FD干扰目标进程 - 子进程继承父进程的文件描述符表副本,但
lsof扫描的是当前时刻的全局状态,可能漏掉刚关闭或刚创建的FD - 解析
lsof输出需正则匹配,字段顺序和格式随版本变化(如lsof -F机器可读格式也非完全稳定) - 启动新进程本身就有竞争条件:从fork到exec之间,原进程FD表已变化
真正需要精确控制时,必须走/proc/self/fd + fcntl这条路径。复杂点在于错误处理要细粒度——每个readdir、readlink、dup、fcntl都可能失败,不能假设连续成功。

















