我在C/linux中有一个socket服务器。每次创建新的socket时,会分配一个文件描述符。我想用这些FD作为每个客户端的唯一标识。如果它们保证始终按升序分配(在我运行的Ubuntu上是这样),那么我可以将它们用作数组索引。
问题是:从Linux sockets分配的文件描述符是否保证始终按升序分配?
问题是:从Linux sockets分配的文件描述符是否保证始终按升序分配?
让我们来看一下这个是如何在内部工作的(我使用的是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);
在这一点上,它们将会重新单调地增长。
希望这能帮到您。
FD在socket的生命周期内保证唯一。所以理论上,您可能可以将FD用作客户端数组的索引。但是,我要提出至少两个原因来警告您不要这样做:
正如已经说过的那样,无法保证FD将被单调地分配。 accept()有权返回高编号的FD,这将使您的数组变得低效。 回答您的问题:不,不能保证它们单调递增。
您的服务器很可能会拥有许多其他打开的FD - 包括标准输入,标准输出和标准错误输出 - 因此,您的数组会浪费空间。
我建议使用其他方式将FD映射到客户端。实际上,除非您需要处理数千个客户端,否则搜索客户端列表应该很好 - 这不是您需要频繁执行的操作。