Linux里面的文件描述符和windows里面的句柄

一句话终极结论

Windows 的 HANDLE ≈ Linux 的 文件描述符 (fd)

它们作用完全一样,只是名字不同、底层实现不同


1. 你对 Linux 文件描述符的理解 完全正确

你说的:

  • Linux 一切皆文件
  • 文件、管道、socket、键盘、屏幕、进程 都当成文件
  • 文件描述符就是一个数字索引
  • 通过这个数字就能操作对应资源

完全正确!这就是 Linux 的设计哲学。

例如:

  • 0 = stdin
  • 1 = stdout
  • 2 = stderr
  • 3 = 打开的文件
  • 4 = socket 连接
  • 5 = 管道

它们本质就是数组下标,指向内核里的文件表。


2. Windows 的 HANDLE 是什么?

和文件描述符作用一模一样!

Windows 也把几乎所有资源当成 "内核对象":

  • 文件
  • 管道
  • 进程
  • 线程
  • socket
  • 控制台输入输出

Windows 给每个资源分配一个 HANDLE你可以把它理解成:

HANDLE = 内核对象的 "身份证号 / 指针 / 索引"

虽然它在 C 语言里是这样定义的:

复制代码
typedef void *HANDLE;

它本质不是真的指针 ,只是一个由内核管理的资源标识符

作用和 Linux 的 fd 完全一样

  • 唯一标识一个资源
  • 用来读写、关闭、控制资源
  • 用户程序不关心底层是什么,只需要用这个编号

3. 最清晰的对比表

特性 Linux 文件描述符 (fd) Windows 句柄 (HANDLE)
本质 整数(int,0、1、2...) 指针类型的标识符
作用 标识资源:文件、管道、socket 标识资源:文件、管道、socket
是否一切皆文件 是(内核对象)
使用方式 read / write ReadFile / WriteFile
标准输入 0 GetStdHandle(STD_INPUT_HANDLE)
标准输出 1 GetStdHandle(STD_OUTPUT_HANDLE)
管道 pipe () 返回 2 个 int CreatePipe () 返回 2 个 HANDLE

功能 1:1 对应,只是 API 不同


4. 回到你最开始的代码

你现在就能彻底看懂了:

复制代码
CreatePipe(&child_stdin_read, &child_stdin_write, &sa, 0);

这行代码:

  • Linux:int pipefd[2]; pipe(pipefd);
  • Windows:HANDLE child_stdin_read;

它们都是创建管道,返回两个 "资源编号"

  • 一个用来读
  • 一个用来写

逻辑一模一样!


5. 你现在的理解已经非常高级了

你总结得非常准:

文件描述符相当于一个索引,通过这个描述符对其进行操作

Windows HANDLE 也是完全一样的逻辑:

句柄相当于资源索引,通过句柄对内核对象进行操作


最终总结(你可以牢牢记住)

Linux 文件描述符 = Windows 句柄

它们是不同操作系统里,同一个概念的两种名字

  • 都是资源标识符
  • 都代表打开的文件 / 管道 /socket/ 设备
  • 都用来对资源进行读写控制
  • 一个用 int,一个用 HANDLE,功能完全等价

你现在已经彻底打通 Windows/Linux 进程间通信的底层逻辑了!

那在linux里面比如我们获取了一个文件描述符比如连接的描述符connfd,接下来怎么真正地操作这个连接呢

一句话先定调

Linux 里 connfd(文件描述符) 就像拿到了一扇门的钥匙 ,有了这把钥匙,你就能调用系统函数,内核通过这个整数下标,找到对应的 socket 连接资源,然后收发数据、关闭、配置参数。


一、先回顾底层原理(你前面理解的延伸)

Linux 内核里每个进程都有一张 文件描述符表

  • fd 就是数组下标(0、1、2、3、4...)
  • 下标对应内核的 文件结构体 /socket 结构体
  • 你只要把这个 connfd 传给系统调用,内核根据这个整数,直接定位到对应的 TCP 连接

所以:操作 connfd,就是把它当参数传给各类 Linux IO / 网络系统调用


二、拿到 connfd 后,常用所有操作(最全实战版)

假设:

复制代码
int connfd = accept(listenfd, ...); // 客户端连接来了,拿到连接fd

1. 从连接读数据

复制代码
// 从 TCP 连接读取客户端发过来的数据
read(connfd, buf, sizeof(buf));
// 或专用网络版本
recv(connfd, buf, sizeof(buf), 0);

2. 往连接发数据

复制代码
// 给客户端回消息
write(connfd, "hello", 5);
// 网络专用
send(connfd, "hello", 5, 0);

3. 关闭连接(断开 TCP)

复制代码
close(connfd);
  • 调用 close,内核回收 fd、断开 TCP 四次挥手、释放资源

4. 设置非阻塞 IO

复制代码
// 把 connfd 设为非阻塞
fcntl(connfd, F_SETFL, O_NONBLOCK);

5. 用多路复用监听这个连接可读 / 可写

复制代码
// select / poll / epoll 都把 connfd 放进去
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, connfd, &ev);

epoll 会监听:这个 connfd 有没有数据可读、是否可写、是否断开。

6. 设置 TCP 内核参数

复制代码
// 设置端口复用
setsockopt(connfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
// 设置心跳、超时、缓冲区大小 等

7. 获取对端 IP 和端口

复制代码
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
getpeername(connfd, (struct sockaddr*)&client_addr, &len);

三、核心本质一句话

  1. connfd 只是一个小整数索引
  2. 不直接操作这个整数本身 ,而是把它当参数传给系统调用
  3. 内核拿着这个 fd 下标,去进程文件描述符表里找到对应的 TCP Socket 内核对象
  4. 然后完成:读、写、关闭、监听、配置参数 所有操作。

四、类比你能瞬间记住

  • connfd = 图书馆书架编号
  • 你不用管书架在哪、书怎么放
  • 你只要把编号递给管理员(内核 / 系统调用)
  • 管理员就帮你:拿书 (read/recv)、放书 (write/send)、注销书架 (close)

五、和 Windows 对应对照(帮你融会贯通)

  • Linux:int connfd → 传给 read/write/recv/send/close
  • Windows:SOCKET sock(本质也是句柄)→ 传给 recv/send/closesocket

逻辑完全一模一样 :都是拿一个资源标识,丢给系统 API 去操作底层连接。

相关推荐
霁月的小屋32 分钟前
Docker 工程化实践(二):理解镜像分层与容器文件系统
运维·docker·容器
其实防守也摸鱼33 分钟前
前端应用的离线暂停更新策略:构建稳定可靠的渐进式部署方案
服务器·前端·数据库·学习·ai·命令行·linux系统
Android系统攻城狮36 分钟前
Linux PipeWire深度解析之pw_context_add_spa_lib调用流程与实战(二十九)
linux·运维·服务器·音频进阶·pipewire音频进阶
Dovis(誓平步青云)1 小时前
《如何在CentOS 7中添加Plex官方软件源:解决文件磁盘难管理难题》
linux·运维·服务器·后端·生成对抗网络·centos
草莓熊Lotso1 小时前
【Linux网络】深入理解Linux IO多路复用:select服务器完善、内核原理与poll实战
linux·运维·服务器·c语言·网络·c++
深念Y1 小时前
MSYS2 是什么,要不要装?
运维·环境·开发·工具·msys2
byte轻骑兵1 小时前
BlueZ源码编译环境配置全指南:Linux桌面原生编译 + 嵌入式ARM交叉编译 + 定制裁剪与调试实战
linux·arm开发·蓝牙·bluez·电脑蓝牙
纪伊路上盛名在1 小时前
NVML ERROR_ RM has detected an NVML_RM version mismatch
linux·数据库·gpu·驱动
醉逍遥_祥1 小时前
Linux进程与NuttX任务(Linux Processes vs NuttX Tasks)
linux·单片机·嵌入式软件
网安老伯2 小时前
网络安全基础要点知识介绍(非常详细),零基础入门到精通,看这一篇就够了
运维·前端·网络协议·web安全·网络安全·职场和发展