Linux套接字的文件描述符总是按递增顺序排列

Jos*_*ain 3 sockets linux file-descriptor

我在C/linux中有一个套接字服务器.每次我创建一个新套接字时,都会为其分配一个文件描述符.我想将这些FD用作每个客户端的唯一ID.如果保证它们总是按递增顺序分配(我正在运行的Ubuntu就是这种情况)那么我可以将它们用作数组索引.

所以问题是:从linux套接字分配的文件描述符是否始终保持递增顺序?

小智 5

让我们看看它是如何在内部工作的(我正在使用内核4.1.20).在Linux中分配文件描述符的方式是使用__alloc_fd.当您执行打开的系统调用时,将调用do_sys_open.此例程从get_unused_fd_flags获取一个空闲文件描述符:

long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{ 
    ...
    fd = get_unused_fd_flags(flags);
    if (fd >= 0) {
        struct file *f = do_filp_open(dfd, tmp, &op);
Run Code Online (Sandbox Code Playgroud)

get_unused_d_flags调用__alloc_fd设置最小和最大fd:

int get_unused_fd_flags(unsigned flags)
{
    return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags);
}
Run Code Online (Sandbox Code Playgroud)

__alloc_fd获取进程的文件描述符表,并将fd作为next_fd获取,该实际上是从上一次运行时设置的:

int __alloc_fd(struct files_struct *files,
           unsigned start, unsigned end, unsigned flags)
{
    ...
    fd = files->next_fd;
    ...
    if (start <= files->next_fd)
        files->next_fd = fd + 1;
Run Code Online (Sandbox Code Playgroud)

所以你可以看到文件描述符的确是单调增长的......直到某一点.当fd达到最大值时,__ alloc_fd将尝试查找最小的未使用文件描述符:

if (fd < fdt->max_fds)
    fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, fd);
Run Code Online (Sandbox Code Playgroud)

此时,文件描述符将不再单调增长,而是跳转尝试查找空闲文件描述符.在此之后,如果表格已满,它将被展开:

error = expand_files(files, fd);
Run Code Online (Sandbox Code Playgroud)

在这一点上,他们将再次单调地增长.

希望这可以帮助


ric*_*vdh 4

FD 在套接字的生命周期内保证是唯一的。所以,是的,理论上,您可以使用 FD 作为客户端数组的索引。不过,我至少出于以下几个原因对此提出警告:

  • 正如已经说过的,不能保证FD会被单调分配。Accept() 有权返回一个高编号的 FD,这会使你的数组​​效率低下。对你的问题的简短回答:不,它们不能保证是单调的。

  • 您的服务器可能最终会出现许多其他打开的 FD - stdin、stdout 和 stderr 仅举三个 - 因此,您的阵列又浪费了空间。

我建议使用其他一些从 FD 映射到客户端的方法。事实上,除非您要与数千个客户打交道,否则搜索客户列表应该没问题 - 这实际上并不是您需要执行大量操作的操作。

  • 另外,套接字(和文件描述符)是一种宝贵的资源,当不再需要它们时,您应该释放(即“关闭”)它们。典型的 Linux 进程通常只能有几千个 fd-s(该限制可以提高)。如果您的应用程序将“关闭”一个 fd,内核可能会在稍后重新分配它...所以从长远来看,fd-s *不是*单调分配的... (2认同)