Linux通过/proc/self/fd和/proc/self/fdinfo可精确获取句柄路径、类型及flags/pos等元数据;Windows需调用NtQuerySystemInformation等非公开API,仅能获得基础类型且无等效flags或pos信息,跨平台封装必须接受信息不对称。

Linux下用/proc/self/fd读取句柄基本信息最直接
Linux内核通过/proc/self/fd为每个进程暴露符号链接形式的打开文件列表,这是获取句柄路径、类型(如socket、pipe、regular file)的最快方式。注意:它不提供“状态”如read/write权限或锁信息,只反映内核当前持有的fd编号与目标对象的映射关系。
实操建议:
- 遍历
/proc/self/fd/目录,对每个readlink()得到目标路径;若失败(如readlink: Permission denied),说明是匿名资源(如[eventpoll]、[timerfd]、[anon_inode:]) - 用
stat()检查目标路径是否为socket、fifo、chr、blk等,区分类型;但对[socket:<pid>]</pid>这类伪路径,需结合/proc/self/fdinfo/<fd></fd>进一步判断 - 不要依赖
ls -l /proc/self/fd输出中的权限字段——那是符号链接本身的权限,不是fd的访问模式
/proc/self/fdinfo/<fd></fd>里才有真正的打开状态细节
/proc/self/fdinfo/<fd></fd>包含每个fd的详细元数据:flags(O_RDONLY/O_WRONLY/O_RDWR/O_CLOEXEC等)、pos(文件偏移)、mnt_id、inode,对socket还有st_uid、st_gid、st_mode等。这是唯一能确认“是否可写”“是否设置了close-on-exec”的地方。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 误以为
open("/dev/null", O_WRONLY)创建的fd在/proc/self/fd中显示为/dev/null就代表可写——实际必须查fdinfo里的flags字段是否有O_WRONLY - 读取
fdinfo时忽略errno == ENOENT:fd可能在读取瞬间已被关闭,需容错处理 - 把
pos当成实时位置:对pipe/socket该值恒为0,仅对seekable文件有意义
Windows上只能靠NtQuerySystemInformation + GetFileType拼凑
Windows没有等价于/proc的轻量级接口。必须调用未公开的NtQuerySystemInformation(SystemHandleInformation, ...)获取全系统句柄表,再过滤出当前进程PID的条目,最后用GetFileType()和GetNamedPipeInfo()等逐个探测类型。过程繁琐且易受UAC和权限限制影响。
使用场景限制:
- 需要管理员权限才能查询其他进程句柄;查询自身进程也常因句柄继承或沙盒策略失败
-
NtQuerySystemInformation不是稳定API,Windows 11 22H2后部分字段含义变动,ObjectTypeNumber不再可靠对应FILE/EVENT等 - 无法获取类似Linux的
fdinfo中flags或pos——Windows句柄本身不携带打开模式元数据,只靠GetFileInformationByHandle能拿到基本属性,但无法反推CreateFile时传的dwDesiredAccess
C++跨平台封装的关键取舍点
想用同一套C++代码在Linux/Windows都跑通,必须接受信息不对称:Linux能拿到完整fd+fdinfo,Windows最多做到“列出句柄号+基础类型+是否有效”。硬要统一字段会误导使用者。
实操建议:
- Linux分支优先解析
/proc/self/fd和/proc/self/fdinfo,字段命名直译(如fd_flags、fd_pos) - Windows分支放弃
flags和pos字段,用GetFileType()返回FILE_TYPE_DISK/FILE_TYPE_PIPE等,并对INVALID_HANDLE_VALUE做显式过滤 - 避免封装成
get_all_handles()这种假统一接口——调用方必须清楚Linux返回的是vector<FdInfo>,Windows返回的是vector<WinHandleInfo>,二者字段集本质不同
真正难的不是读取,而是理解每条信息的边界:Linux的fdinfo里flags精确到每个fd的打开参数,而Windows连“这个句柄当初是不是以OVERLAPPED方式创建的”都无法回溯。别指望跨平台抽象能抹平这种差异。


















