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 发行版中。
我遵循了如何使用 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 发行版中。