繁体   English   中英

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

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

I followed a tutorial on how to make two processes on Linux communicate using the Linux Sockets API, and that's the code it showed to make it happen:

连接代码:

char* socket_path = "\0hidden";
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 = '\0';
strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));

监听代码:

char* socket_path = "\0hidden";
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 = '\0';
strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
bind(fd, (struct sockaddr*)&addr, sizeof(addr));
listen(fd, 5);

Basically, I have written a web server for a website in C, and a database management system in C++, and making them communicate (after a user's browser sends an HTTP request to my web server, which it's listening for using an AF_INET family socket,但这在这里并不重要,只是一些上下文)使用这种机制。数据库系统正在使用其套接字进行侦听,并且 web 服务器使用自己的套接字连接到它。 它一直工作得很好。

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

如果有人能解释一下一直让我迷惑不解的 Linux Sockets API,我将不胜感激。 我用谷歌搜索并查看了多个地方,每个人似乎都只是在使用"\0hidden"而没有解释它,好像这是每个人都应该知道的一些基本知识。 就像,我在这里遗漏了一些理论还是什么? 非常感谢任何提前解释的人!

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

所以我 memory socket_path实际上看起来像这样:

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

因为所有字符串都会自动附加一个终止的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 ,所以实际路径仍然是\0hidden

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

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

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

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

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

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

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

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

有关详细信息,请参阅

man 7 unix

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM