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

5
我在C/linux中有一个socket服务器。每次创建新的socket时,会分配一个文件描述符。我想用这些FD作为每个客户端的唯一标识。如果它们保证始终按升序分配(在我运行的Ubuntu上是这样),那么我可以将它们用作数组索引。
问题是:从Linux sockets分配的文件描述符是否保证始终按升序分配?
3个回答

12

让我们来看一下这个是如何在内部工作的(我使用的是4.1.20内核)。在Linux中,文件描述符的分配方式是通过__alloc_fd进行的。当您执行open系统调用时,会调用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);

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

int get_unused_fd_flags(unsigned flags)
{
    return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags);
}

__alloc_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;

因此,您可以看到文件描述符确实会单调增长......直到某个点。当fd达到最大值时,__alloc_fd将尝试查找最小的未使用的文件描述符:

if (fd < fdt->max_fds)
    fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, fd);

到了这一点,文件描述符将不再单调递增,而是会跳跃地寻找空闲的文件描述符。如果表已经满了,它将被扩展:

error = expand_files(files, fd);

在这一点上,它们将会重新单调地增长。

希望这能帮到您。


4

FD在socket的生命周期内保证唯一。所以理论上,您可能可以将FD用作客户端数组的索引。但是,我要提出至少两个原因来警告您不要这样做:

  • 正如已经说过的那样,无法保证FD将被单调地分配。 accept()有权返回高编号的FD,这将使您的数组变得低效。 回答您的问题:不,不能保证它们单调递增。

  • 您的服务器很可能会拥有许多其他打开的FD - 包括标准输入,标准输出和标准错误输出 - 因此,您的数组会浪费空间。

我建议使用其他方式将FD映射到客户端。实际上,除非您需要处理数千个客户端,否则搜索客户端列表应该很好 - 这不是您需要频繁执行的操作。


2
另外,套接字(和文件描述符)是一种宝贵的资源,当不再需要时应该释放(即“关闭”)。一个典型的Linux进程通常只能拥有几千个fd(该限制可以提高)。如果您的应用程序将关闭一个fd,则内核可能会稍后重新分配它...因此从长远来看,fd并没有单调分配... - Basile Starynkevitch
谢谢。服务器代码旨在为几千个用户提供服务。线性搜索并不是真正可行的。我本质上是在尝试高效地解决设计和数据结构问题。我的帖子在这里:http://stackoverflow.com/questions/9373739/what-is-the-fastest-way-to-find-an-integer-in-an-array。顺便说一句,有人把我的帖子标题改成了一些愚蠢的东西。 - Josh Brittain
总之,我需要将用户组织成15个一组,然后快速确定用户所在的组。我能想到的唯一方法是双重哈希,首先根据userID进行哈希,然后再根据groupID进行第二次哈希。 - Josh Brittain

2
不要依赖文件描述符的单调性。始终通过地址:端口对引用远程系统。

你能详细解释一下吗?FD(文件描述符)不保证唯一吗?如果它们不是唯一的,那么在等待FD的I/O时是否会导致错误? - Josh Brittain
1
@Josh Brittain:当有人使用Cygwin或其他移植层将你的软件移植到Windows时会发生什么?请记住,这个人可能就是你自己。使用哈希表,因为fd必须是唯一的才能正常工作。 - JimR
谢谢JimR。我正在考虑哈希表,认为这可能更好。看来我又回到了散列 :) - Josh Brittain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接