文件描述符的分配与重用

文件描述符的分配与重用解析

前言

本篇将结合代码,着重解析文件描述符的回收与重用。

关于文件描述符分配机制部分的介绍可以看前文。

【网络io与io多路复用(3)】 Linux与文件描述符(FD)-优快云博客


1. 文件描述符的回收与重用

当关闭一个文件描述符(如 close(clientfd))时,内核会将其标记为可用状态,供后续分配使用。文件描述符的重用行为取决于以下因素:

立即重用:如果关闭文件描述符后立即重新分配,内核可能会优先分配刚刚释放的文件描述符。

延迟重用:如果关闭文件描述符后等待一段时间再重新分配,内核可能会分配其他可用的文件描述符。

2. 代码演示与运行结果

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
    int fd1 = open("file1.txt", O_CREAT | O_RDWR, 0644);
    int fd2 = open("file2.txt", O_CREAT | O_RDWR, 0644);
    int fd3 = open("file3.txt", O_CREAT | O_RDWR, 0644);

    printf("fd1=%d, fd2=%d, fd3=%d\n", fd1, fd2, fd3);

    close(fd2); // 关闭 fd2

    int fd4 = open("file4.txt", O_CREAT | O_RDWR, 0644);
    printf("fd4=%d\n", fd4); // 输出 fd4

    sleep(5); // 等待一段时间

    int fd5 = open("file5.txt", O_CREAT | O_RDWR, 0644);
    printf("fd5=%d\n", fd5); // 输出 fd5

    close(fd1);
    close(fd3);
    close(fd4);
    close(fd5);

    return 0;
}

3. 代码拆解

文件描述符的初始分配

程序首先打开三个文件,分别返回文件描述符 fd1、fd2、fd3。

由于标准输入(0)、标准输出(1)、标准错误(2)已经被占用,新打开的文件描述符从 3 开始分配。

因此,fd1=3、fd2=4、fd3=5。

int fd1 = open("file1.txt", O_CREAT | O_RDWR, 0644); // fd1=3
int fd2 = open("file2.txt", O_CREAT | O_RDWR, 0644); // fd2=4
int fd3 = open("file3.txt", O_CREAT | O_RDWR, 0644); // fd3=5
printf("fd1=%d, fd2=%d, fd3=%d\n", fd1, fd2, fd3);   // 输出:fd1=3, fd2=4, fd3=5

关闭文件描述符并立即重新分配

程序关闭 fd2(即文件描述符 4),释放该文件描述符。

立即打开一个新文件 file4.txt,内核会分配当前可用的最小文件描述符。

由于 4 刚刚被释放,内核会优先分配 4,因此 fd4=4。

close(fd2); // 关闭 fd2(4)
int fd4 = open("file4.txt", O_CREAT | O_RDWR, 0644); 
printf("fd4=%d\n", fd4); // 输出fd4

等待一段时间后重新分配

程序调用 sleep(5),等待 5 秒。

打开一个新文件 file5.txt,内核会分配当前可用的最小文件描述符。

由于 0~5 已经被重新分配,内核会分配下一个可用的文件描述符 6,因此fd5=6。

sleep(5); // 等待 5 秒
int fd5 = open("file5.txt", O_CREAT | O_RDWR, 0644); 
printf("fd5=%d\n", fd5); // 输出fd5

文件描述符的关闭

程序关闭所有打开的文件描述符,释放资源。

close(fd1);
close(fd3);
close(fd4);
close(fd5);

4. 内核行为解释

最小可用原则:内核总是优先分配当前可用的最小文件描述符。

文件描述符的缓存与回收:内核可能会缓存最近释放的文件描述符,以便快速重用。但在某些情况下(如延迟回收),内核可能会跳过缓存的文件描述符,分配其他可用的文件描述符。

5. 总结

(1)文件描述符的分配遵循最小可用原则。

(2)关闭文件描述符后,内核可能会立即重用或延迟重用该文件描述符。

(3)这种行为体现了内核的资源管理策略,包括文件描述符的缓存、延迟回收和最小可用原则。

学习资料参考

https://github.com/0voice

<think> 在Windows中,SOCKET类型实际上是一个整数句柄(类似于文件描述符),但它不是POSIX标准中的文件描述符。Windows的SOCKET句柄和文件描述符在概念上类似,但管理方式不同。 关键点: 1. Windows的SOCKET句柄由Winsock管理,而文件描述符由C运行时库管理(如使用_open、_open_osfhandle等)。 2. 当使用socket函数创建套接字时,返回的是一个SOCKET句柄,这个句柄在进程内是唯一的,直到你关闭它。 3. 关闭套接字使用closesocket,而不是close(除非你将SOCKET句柄转换为C运行时的文件描述符使用_close,但一般不这样做)。 4. 当关闭一个SOCKET后,该句柄值会被系统回收,后续创建的套接字可能会重用这个值(即重复使用)。因此,在关闭套接字后,不应该再使用该句柄。 因此,答案是:会重复。当套接字关闭后,其句柄值可能会被后续新创建的套接字重复使用。 示例说明: 假设我们创建了一个套接字,得到句柄值1000,然后关闭它。之后当我们再创建一个新的套接字时,系统可能会将1000重新分配给新的套接字。 注意事项: 在编程中,我们应当注意,一旦关闭了套接字,就不要再使用该句柄。尤其是在多线程环境下,如果其他线程还在使用该句柄,可能会导致不可预知的错误。 Linux的区别: 在Linux中,套接字是文件描述符的一种,文件描述符关闭后也会被后续的打开操作(包括创建套接字、打开文件等)重复使用。 结论: 在Windows中,SOCKET句柄在关闭后会被系统回收可能重新分配给新的套接字,因此会重复。 §§相关问题§§ 1. Windows中SOCKET句柄和文件描述符之间如何转换? 2. 在Windows中,如何避免使用已关闭的套接字句柄导致的错误? 3. 除了select模型,Windows还有哪些I/O多路复用机制可以处理大量发连接? </think>在Windows系统中,Socket分配文件描述符(实际上是SOCKET句柄)**会重复使用**。以下是关键说明: 1. **SOCKET句柄回收机制**: - 当调用`closesocket()`关闭连接后,系统会将该SOCKET句柄标记为可重用 - 新创建的Socket可能被分配**之前使用过的相同数值** - 这Linux文件描述符回收机制类似 2. **句柄管理特点**: ```cpp SOCKET s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 假设分配0x100 closesocket(s1); SOCKET s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 可能再次分配0x100 ``` 3. **注意事项**: - 重复使用不会立即发生(系统会有短暂延迟) - 已关闭的句柄若被误用会导致`WSAENOTSOCK`错误 - 使用`INVALID_SOCKET`(值-1)作为无效句柄标识 4. **Linux区别**: | 特性 | Windows | Linux | |--------------|---------------------|-----------------| | 句柄类型 | 独立SOCKET类型 | int文件描述符 | | 关闭函数 | `closesocket()` | `close()` | | 无效值标识 | `INVALID_SOCKET`(-1)| `-1` | 5. **编程建议**: - 关闭Socket后立即将变量设为`INVALID_SOCKET` - 使用`WSAStartup`/`WSACleanup`管理资源生命周期 - 在多线程环境中需加锁保护句柄操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值