AF_UNIX 套接字路径中“\0hidden”的用途是什么?

What is the purpose of "\0hidden" in an AF_UNIX socket path?

我遵循了如何使用 Linux 套接字 API 使 Linux 上的两个进程进行通信的教程,这就是实现它的代码:

连接码:

char* socket_path = "[=11=]hidden";
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr;
memset(&addr, 0x0, sizeof(addr));
addr.sun_family = AF_UNIX;
*addr.sun_path = '[=11=]';
strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));

听力代码:

char* socket_path = "[=12=]hidden";
struct sockaddr_un addr;
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
memset(&addr, 0x0, sizeof(addr));
addr.sun_family = AF_UNIX;
*addr.sun_path = '[=12=]';
strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
bind(fd, (struct sockaddr*)&addr, sizeof(addr));
listen(fd, 5);

基本上,我已经用 C 为网站编写了一个 Web 服务器,用 C++ 编写了一个数据库管理系统,并使它们进行通信(在用户浏览器向我的 Web 服务器发送 HTTP 请求后,它正在侦听使用一个 AF_INET 系列套接字,但这在这里并不重要,只是一些上下文)使用这个 mechanism.The 数据库系统正在使用它的套接字进行侦听,并且 Web 服务器使用它自己的套接字连接到它。它一直运行良好。

但是,我一直不明白套接字路径开头的空字节的用途是什么。比如,"[=13=]hidden" 到底是什么意思,或者它有什么作用?我阅读了有关套接字的联机帮助页,它说了一些关于虚拟套接字的内容,但它对我来说太技术化了,无法了解正在发生的事情。我也不清楚将套接字表示为具有文件描述符的文件的概念。我也不明白 strncpy() 的作用。我什至不明白 Web 服务器如何使用此代码块找到数据库系统,是因为它们的进程都是从同一目录中的可执行文件启动的,还是因为数据库系统是整个系统中唯一监听的进程在 AF_UNIX 插座上,或者什么?

如果有人能解释一下 Linux 套接字 API 中让我迷惑了这么久的这一部分,我将不胜感激。我用谷歌搜索并查看了多个地方,每个人似乎只是在使用 "[=13=]hidden" 而没有解释它,就好像这是每个人都应该知道的一些基本知识一样。比如,我是不是漏掉了一些理论或者什么?非常感谢任何人提前解释!

[=12=] 只是将一个 NUL 字符放入字符串中。由于 NUL 字符用于终止字符串,因此对于所有 C 字符串函数, socket_path 看起来像一个空字符串,而实际上它不是,但它们会在第一个字符后停止处理它。

所以我的记忆socket_path实际上是这样的:

char socket_path[] = { `[=10=]`, `h`, `i`, `d`, `d`, `e`, `n`, `[=10=]` };

因为所有字符串都会自动附加终止符 NUL

strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);

socket_path 的字节复制到套接字地址结构 addr,但跳过第一个 (NUL) 字节以及最后一个字节(也 NUL ).因此套接字的地址实际上就是单词 "hidden".

但是由于addr.sun_path也遗漏了第一个字节,并且这个字节之前已经被memset初始化为NUL,所以实际路径仍然是[=26 =]hidden.

那么为什么会有人这样做呢?可能是为了隐藏套接字,因为通常系统将文件系统中的 UNIX 套接字显示为实际路径条目,但我知道没有文件系统可以处理 [=12=] 字符。所以如果名称有一个 [=12=] 字符,它不会出现在文件系统中,但这样的字符只允许作为第一个字符,否则系统仍然会尝试创建该路径条目并失败因此套接字创建将失败。仅作为第一个字符,系统甚至不会尝试创建它,这意味着您无法通过在终端中调用 ls 来看到该套接字,任何想要连接到它的人都需要知道名称。

请注意,这不符合 POSIX,因为 POSIX 期望 UNIX 套接字始终出现在文件系统中,因此只允许使用文件系统合法的字符作为套接字姓名。这仅适用于 Linux.

这特定于 AF_UNIX 本地套接字的 Linux 内核实现。如果给出套接字名称的字符数组是空字符串,则该名称不引用文件系统名称中的任何内容space;字符数组的剩余字节被视为位于内核内存中的内部名称。请注意,此名称不是以 null 结尾的;字符数组中的所有字节都是有意义的,无论它们的值如何。 (因此,您的示例程序在复制名称之前将结构的 memset 字节归零是一件好事。)

这允许应用程序命名套接字集合点,这些集合点不占用文件系统中的节点,因此更类似于 TCP 或 UDP 端口号(也不位于文件系统中)。当所有引用它们的套接字关闭时,这些集合点会自动消失。

文件系统中的节点有一些缺点。创建和访问它们需要存储设备。为防止这种情况,可以在 RAM 中的临时文件系统中创建它们,例如 tmpfs in Linux;但是 tmpfs 条目几乎肯定比 AF_UNIX 实现中的专用条目访问更慢并且占用更多 RAM。如果应用程序崩溃,临时需要的套接字(例如当应用程序 运行 时)可能会保留下来,需要外部干预来清理它们。

hidden 可能不是套接字的好名称;程序应该利用 space 并使用一些准保证不会与其他任何人发生冲突的东西。该名称允许超过 100 个字符,因此使用某种 UUID 字符串可能是个好主意。

Linux程序员手册man页面称这种地址为“抽象”。它与“未命名”截然不同。

任何标准 AF_UNIX 实现都提供“未命名”套接字,可以通过两种方式创建:任何 AF_UNIX 已使用 socket 创建但未使用 [ 指定地址的套接字=21=] 未命名; socketpair 创建的一对套接字未命名。

有关详细信息,请参阅

man 7 unix

在安装了 Linux 手册页的某些 GNU/Linux 发行版中。